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;
1049 MonoCustomAttrInfo *ainfo;
1051 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1052 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1055 for (i = 0; i < ainfo->num_attrs; ++i) {
1056 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1057 if (klass->image == mono_defaults.corlib) {
1058 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1059 mono_custom_attrs_free (ainfo);
1060 return SPECIAL_STATIC_THREAD;
1062 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1063 mono_custom_attrs_free (ainfo);
1064 return SPECIAL_STATIC_CONTEXT;
1068 mono_custom_attrs_free (ainfo);
1069 return SPECIAL_STATIC_NONE;
1072 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1073 #define mix(a,b,c) { \
1074 a -= c; a ^= rot(c, 4); c += b; \
1075 b -= a; b ^= rot(a, 6); a += c; \
1076 c -= b; c ^= rot(b, 8); b += a; \
1077 a -= c; a ^= rot(c,16); c += b; \
1078 b -= a; b ^= rot(a,19); a += c; \
1079 c -= b; c ^= rot(b, 4); b += a; \
1081 #define final(a,b,c) { \
1082 c ^= b; c -= rot(b,14); \
1083 a ^= c; a -= rot(c,11); \
1084 b ^= a; b -= rot(a,25); \
1085 c ^= b; c -= rot(b,16); \
1086 a ^= c; a -= rot(c,4); \
1087 b ^= a; b -= rot(a,14); \
1088 c ^= b; c -= rot(b,24); \
1092 * mono_method_get_imt_slot:
1094 * The IMT slot is embedded into AOTed code, so this must return the same value
1095 * for the same method across all executions. This means:
1096 * - pointers shouldn't be used as hash values.
1097 * - mono_metadata_str_hash () should be used for hashing strings.
1100 mono_method_get_imt_slot (MonoMethod *method)
1102 MONO_REQ_GC_NEUTRAL_MODE;
1104 MonoMethodSignature *sig;
1106 guint32 *hashes_start, *hashes;
1110 /* This can be used to stress tests the collision code */
1114 * We do this to simplify generic sharing. It will hurt
1115 * performance in cases where a class implements two different
1116 * instantiations of the same generic interface.
1117 * The code in build_imt_slots () depends on this.
1119 if (method->is_inflated)
1120 method = ((MonoMethodInflated*)method)->declaring;
1122 sig = mono_method_signature (method);
1123 hashes_count = sig->param_count + 4;
1124 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1125 hashes = hashes_start;
1127 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1128 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1129 method->klass->name_space, method->klass->name, method->name);
1132 /* Initialize hashes */
1133 hashes [0] = mono_metadata_str_hash (method->klass->name);
1134 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1135 hashes [2] = mono_metadata_str_hash (method->name);
1136 hashes [3] = mono_metadata_type_hash (sig->ret);
1137 for (i = 0; i < sig->param_count; i++) {
1138 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1141 /* Setup internal state */
1142 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1144 /* Handle most of the hashes */
1145 while (hashes_count > 3) {
1154 /* Handle the last 3 hashes (all the case statements fall through) */
1155 switch (hashes_count) {
1156 case 3 : c += hashes [2];
1157 case 2 : b += hashes [1];
1158 case 1 : a += hashes [0];
1160 case 0: /* nothing left to add */
1164 free (hashes_start);
1165 /* Report the result */
1166 return c % MONO_IMT_SIZE;
1175 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1176 MONO_REQ_GC_NEUTRAL_MODE;
1178 guint32 imt_slot = mono_method_get_imt_slot (method);
1179 MonoImtBuilderEntry *entry;
1181 if (slot_num >= 0 && imt_slot != slot_num) {
1182 /* we build just a single imt slot and this is not it */
1186 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1187 entry->key = method;
1188 entry->value.vtable_slot = vtable_slot;
1189 entry->next = imt_builder [imt_slot];
1190 if (imt_builder [imt_slot] != NULL) {
1191 entry->children = imt_builder [imt_slot]->children + 1;
1192 if (entry->children == 1) {
1193 mono_stats.imt_slots_with_collisions++;
1194 *imt_collisions_bitmap |= (1 << imt_slot);
1197 entry->children = 0;
1198 mono_stats.imt_used_slots++;
1200 imt_builder [imt_slot] = entry;
1203 char *method_name = mono_method_full_name (method, TRUE);
1204 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1205 method, method_name, imt_slot, vtable_slot, entry->children);
1206 g_free (method_name);
1213 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1215 MonoMethod *method = e->key;
1216 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1220 method->klass->name_space,
1221 method->klass->name,
1224 printf (" * %s: NULL\n", message);
1230 compare_imt_builder_entries (const void *p1, const void *p2) {
1231 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1232 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1234 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1238 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1240 MONO_REQ_GC_NEUTRAL_MODE;
1242 int count = end - start;
1243 int chunk_start = out_array->len;
1246 for (i = start; i < end; ++i) {
1247 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1248 item->key = sorted_array [i]->key;
1249 item->value = sorted_array [i]->value;
1250 item->has_target_code = sorted_array [i]->has_target_code;
1251 item->is_equals = TRUE;
1253 item->check_target_idx = out_array->len + 1;
1255 item->check_target_idx = 0;
1256 g_ptr_array_add (out_array, item);
1259 int middle = start + count / 2;
1260 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1262 item->key = sorted_array [middle]->key;
1263 item->is_equals = FALSE;
1264 g_ptr_array_add (out_array, item);
1265 imt_emit_ir (sorted_array, start, middle, out_array);
1266 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1272 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1273 MONO_REQ_GC_NEUTRAL_MODE;
1275 int number_of_entries = entries->children + 1;
1276 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1277 GPtrArray *result = g_ptr_array_new ();
1278 MonoImtBuilderEntry *current_entry;
1281 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1282 sorted_array [i] = current_entry;
1284 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1286 /*for (i = 0; i < number_of_entries; i++) {
1287 print_imt_entry (" sorted array:", sorted_array [i], i);
1290 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1292 free (sorted_array);
1297 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1299 MONO_REQ_GC_NEUTRAL_MODE;
1301 if (imt_builder_entry != NULL) {
1302 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_thunks) {
1303 /* No collision, return the vtable slot contents */
1304 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1306 /* Collision, build the thunk */
1307 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1310 result = imt_thunk_builder (vtable, domain,
1311 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1312 for (i = 0; i < imt_ir->len; ++i)
1313 g_free (g_ptr_array_index (imt_ir, i));
1314 g_ptr_array_free (imt_ir, TRUE);
1326 static MonoImtBuilderEntry*
1327 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1330 * LOCKING: requires the loader and domain locks.
1334 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1336 MONO_REQ_GC_NEUTRAL_MODE;
1340 guint32 imt_collisions_bitmap = 0;
1341 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1342 int method_count = 0;
1343 gboolean record_method_count_for_max_collisions = FALSE;
1344 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1347 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1349 for (i = 0; i < klass->interface_offsets_count; ++i) {
1350 MonoClass *iface = klass->interfaces_packed [i];
1351 int interface_offset = klass->interface_offsets_packed [i];
1352 int method_slot_in_interface, vt_slot;
1354 if (mono_class_has_variant_generic_params (iface))
1355 has_variant_iface = TRUE;
1357 mono_class_setup_methods (iface);
1358 vt_slot = interface_offset;
1359 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1362 if (slot_num >= 0 && iface->is_inflated) {
1364 * The imt slot of the method is the same as for its declaring method,
1365 * see the comment in mono_method_get_imt_slot (), so we can
1366 * avoid inflating methods which will be discarded by
1367 * add_imt_builder_entry anyway.
1369 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1370 if (mono_method_get_imt_slot (method) != slot_num) {
1375 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1376 if (method->is_generic) {
1377 has_generic_virtual = TRUE;
1382 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1383 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1388 if (extra_interfaces) {
1389 int interface_offset = klass->vtable_size;
1391 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1392 MonoClass* iface = (MonoClass *)list_item->data;
1393 int method_slot_in_interface;
1394 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1395 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1397 if (method->is_generic)
1398 has_generic_virtual = TRUE;
1399 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1401 interface_offset += iface->method.count;
1404 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1405 /* overwrite the imt slot only if we're building all the entries or if
1406 * we're building this specific one
1408 if (slot_num < 0 || i == slot_num) {
1409 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1412 if (imt_builder [i]) {
1413 MonoImtBuilderEntry *entry;
1415 /* Link entries with imt_builder [i] */
1416 for (entry = entries; entry->next; entry = entry->next) {
1418 MonoMethod *method = (MonoMethod*)entry->key;
1419 char *method_name = mono_method_full_name (method, TRUE);
1420 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1421 g_free (method_name);
1424 entry->next = imt_builder [i];
1425 entries->children += imt_builder [i]->children + 1;
1427 imt_builder [i] = entries;
1430 if (has_generic_virtual || has_variant_iface) {
1432 * There might be collisions later when the the thunk is expanded.
1434 imt_collisions_bitmap |= (1 << i);
1437 * The IMT thunk might be called with an instance of one of the
1438 * generic virtual methods, so has to fallback to the IMT trampoline.
1440 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1442 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1445 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1449 if (imt_builder [i] != NULL) {
1450 int methods_in_slot = imt_builder [i]->children + 1;
1451 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1452 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1453 record_method_count_for_max_collisions = TRUE;
1455 method_count += methods_in_slot;
1459 mono_stats.imt_number_of_methods += method_count;
1460 if (record_method_count_for_max_collisions) {
1461 mono_stats.imt_method_count_when_max_collisions = method_count;
1464 for (i = 0; i < MONO_IMT_SIZE; i++) {
1465 MonoImtBuilderEntry* entry = imt_builder [i];
1466 while (entry != NULL) {
1467 MonoImtBuilderEntry* next = entry->next;
1473 /* we OR the bitmap since we may build just a single imt slot at a time */
1474 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1478 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1479 MONO_REQ_GC_NEUTRAL_MODE;
1481 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1485 * mono_vtable_build_imt_slot:
1486 * @vtable: virtual object table struct
1487 * @imt_slot: slot in the IMT table
1489 * Fill the given @imt_slot in the IMT table of @vtable with
1490 * a trampoline or a thunk for the case of collisions.
1491 * This is part of the internal mono API.
1493 * LOCKING: Take the domain lock.
1496 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1498 MONO_REQ_GC_NEUTRAL_MODE;
1500 gpointer *imt = (gpointer*)vtable;
1501 imt -= MONO_IMT_SIZE;
1502 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1504 /* no support for extra interfaces: the proxy objects will need
1505 * to build the complete IMT
1506 * Update and heck needs to ahppen inside the proper domain lock, as all
1507 * the changes made to a MonoVTable.
1509 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1510 mono_domain_lock (vtable->domain);
1511 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1512 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1513 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1514 mono_domain_unlock (vtable->domain);
1515 mono_loader_unlock ();
1520 * The first two free list entries both belong to the wait list: The
1521 * first entry is the pointer to the head of the list and the second
1522 * entry points to the last element. That way appending and removing
1523 * the first element are both O(1) operations.
1525 #ifdef MONO_SMALL_CONFIG
1526 #define NUM_FREE_LISTS 6
1528 #define NUM_FREE_LISTS 12
1530 #define FIRST_FREE_LIST_SIZE 64
1531 #define MAX_WAIT_LENGTH 50
1532 #define THUNK_THRESHOLD 10
1535 * LOCKING: The domain lock must be held.
1538 init_thunk_free_lists (MonoDomain *domain)
1540 MONO_REQ_GC_NEUTRAL_MODE;
1542 if (domain->thunk_free_lists)
1544 domain->thunk_free_lists = (MonoThunkFreeList **)mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1548 list_index_for_size (int item_size)
1551 int size = FIRST_FREE_LIST_SIZE;
1553 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1562 * mono_method_alloc_generic_virtual_thunk:
1564 * @size: size in bytes
1566 * Allocs size bytes to be used for the code of a generic virtual
1567 * thunk. It's either allocated from the domain's code manager or
1568 * reused from a previously invalidated piece.
1570 * LOCKING: The domain lock must be held.
1573 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1575 MONO_REQ_GC_NEUTRAL_MODE;
1577 static gboolean inited = FALSE;
1578 static int generic_virtual_thunks_size = 0;
1582 MonoThunkFreeList **l;
1584 init_thunk_free_lists (domain);
1586 size += sizeof (guint32);
1587 if (size < sizeof (MonoThunkFreeList))
1588 size = sizeof (MonoThunkFreeList);
1590 i = list_index_for_size (size);
1591 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1592 if ((*l)->size >= size) {
1593 MonoThunkFreeList *item = *l;
1595 return ((guint32*)item) + 1;
1599 /* no suitable item found - search lists of larger sizes */
1600 while (++i < NUM_FREE_LISTS) {
1601 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1604 g_assert (item->size > size);
1605 domain->thunk_free_lists [i] = item->next;
1606 return ((guint32*)item) + 1;
1609 /* still nothing found - allocate it */
1611 mono_counters_register ("Generic virtual thunk bytes",
1612 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1615 generic_virtual_thunks_size += size;
1617 p = (guint32 *)mono_domain_code_reserve (domain, size);
1620 mono_domain_lock (domain);
1621 if (!domain->generic_virtual_thunks)
1622 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1623 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1624 mono_domain_unlock (domain);
1630 * LOCKING: The domain lock must be held.
1633 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1635 MONO_REQ_GC_NEUTRAL_MODE;
1637 guint32 *p = (guint32 *)code;
1638 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1639 gboolean found = FALSE;
1641 mono_domain_lock (domain);
1642 if (!domain->generic_virtual_thunks)
1643 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1644 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1646 mono_domain_unlock (domain);
1649 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1651 init_thunk_free_lists (domain);
1653 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1654 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1655 int length = item->length;
1658 /* unlink the first item from the wait list */
1659 domain->thunk_free_lists [0] = item->next;
1660 domain->thunk_free_lists [0]->length = length - 1;
1662 i = list_index_for_size (item->size);
1664 /* put it in the free list */
1665 item->next = domain->thunk_free_lists [i];
1666 domain->thunk_free_lists [i] = item;
1670 if (domain->thunk_free_lists [1]) {
1671 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1672 domain->thunk_free_lists [0]->length++;
1674 g_assert (!domain->thunk_free_lists [0]);
1676 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1677 domain->thunk_free_lists [0]->length = 1;
1681 typedef struct _GenericVirtualCase {
1685 struct _GenericVirtualCase *next;
1686 } GenericVirtualCase;
1689 * get_generic_virtual_entries:
1691 * Return IMT entries for the generic virtual method instances and
1692 * variant interface methods for vtable slot
1695 static MonoImtBuilderEntry*
1696 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1698 MONO_REQ_GC_NEUTRAL_MODE;
1700 GenericVirtualCase *list;
1701 MonoImtBuilderEntry *entries;
1703 mono_domain_lock (domain);
1704 if (!domain->generic_virtual_cases)
1705 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1707 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1710 for (; list; list = list->next) {
1711 MonoImtBuilderEntry *entry;
1713 if (list->count < THUNK_THRESHOLD)
1716 entry = g_new0 (MonoImtBuilderEntry, 1);
1717 entry->key = list->method;
1718 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1719 entry->has_target_code = 1;
1721 entry->children = entries->children + 1;
1722 entry->next = entries;
1726 mono_domain_unlock (domain);
1728 /* FIXME: Leaking memory ? */
1733 * mono_method_add_generic_virtual_invocation:
1735 * @vtable_slot: pointer to the vtable slot
1736 * @method: the inflated generic virtual method
1737 * @code: the method's code
1739 * Registers a call via unmanaged code to a generic virtual method
1740 * instantiation or variant interface method. If the number of calls reaches a threshold
1741 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1742 * virtual method thunk.
1745 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1746 gpointer *vtable_slot,
1747 MonoMethod *method, gpointer code)
1749 MONO_REQ_GC_NEUTRAL_MODE;
1751 static gboolean inited = FALSE;
1752 static int num_added = 0;
1754 GenericVirtualCase *gvc, *list;
1755 MonoImtBuilderEntry *entries;
1759 mono_domain_lock (domain);
1760 if (!domain->generic_virtual_cases)
1761 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1763 /* Check whether the case was already added */
1764 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1767 if (gvc->method == method)
1772 /* If not found, make a new one */
1774 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1775 gvc->method = method;
1778 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1780 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1783 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1789 if (++gvc->count == THUNK_THRESHOLD) {
1790 gpointer *old_thunk = (void **)*vtable_slot;
1791 gpointer vtable_trampoline = NULL;
1792 gpointer imt_trampoline = NULL;
1794 if ((gpointer)vtable_slot < (gpointer)vtable) {
1795 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1796 int imt_slot = MONO_IMT_SIZE + displacement;
1798 /* Force the rebuild of the thunk at the next call */
1799 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1800 *vtable_slot = imt_trampoline;
1802 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1804 entries = get_generic_virtual_entries (domain, vtable_slot);
1806 sorted = imt_sort_slot_entries (entries);
1808 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1812 MonoImtBuilderEntry *next = entries->next;
1817 for (i = 0; i < sorted->len; ++i)
1818 g_free (g_ptr_array_index (sorted, i));
1819 g_ptr_array_free (sorted, TRUE);
1822 #ifndef __native_client__
1823 /* We don't re-use any thunks as there is a lot of overhead */
1824 /* to deleting and re-using code in Native Client. */
1825 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1826 invalidate_generic_virtual_thunk (domain, old_thunk);
1830 mono_domain_unlock (domain);
1833 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1836 * mono_class_vtable:
1837 * @domain: the application domain
1838 * @class: the class to initialize
1840 * VTables are domain specific because we create domain specific code, and
1841 * they contain the domain specific static class data.
1842 * On failure, NULL is returned, and class->exception_type is set.
1845 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1848 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1849 mono_error_cleanup (&error);
1854 * mono_class_vtable_full:
1855 * @domain: the application domain
1856 * @class: the class to initialize
1857 * @error set on failure.
1859 * VTables are domain specific because we create domain specific code, and
1860 * they contain the domain specific static class data.
1863 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1865 MONO_REQ_GC_UNSAFE_MODE;
1867 MonoClassRuntimeInfo *runtime_info;
1869 mono_error_init (error);
1873 if (mono_class_has_failure (klass)) {
1874 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
1878 /* this check can be inlined in jitted code, too */
1879 runtime_info = klass->runtime_info;
1880 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1881 return runtime_info->domain_vtables [domain->domain_id];
1882 return mono_class_create_runtime_vtable (domain, klass, error);
1886 * mono_class_try_get_vtable:
1887 * @domain: the application domain
1888 * @class: the class to initialize
1890 * This function tries to get the associated vtable from @class if
1891 * it was already created.
1894 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1896 MONO_REQ_GC_NEUTRAL_MODE;
1898 MonoClassRuntimeInfo *runtime_info;
1902 runtime_info = klass->runtime_info;
1903 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1904 return runtime_info->domain_vtables [domain->domain_id];
1909 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1911 MONO_REQ_GC_NEUTRAL_MODE;
1913 size_t alloc_offset;
1916 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1917 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1918 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1920 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1921 g_assert ((imt_table_bytes & 7) == 4);
1928 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1932 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1934 MONO_REQ_GC_UNSAFE_MODE;
1937 MonoClassRuntimeInfo *runtime_info, *old_info;
1938 MonoClassField *field;
1940 int i, vtable_slots;
1941 size_t imt_table_bytes;
1943 guint32 vtable_size, class_size;
1945 gpointer *interface_offsets;
1947 mono_error_init (error);
1949 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1950 mono_domain_lock (domain);
1951 runtime_info = klass->runtime_info;
1952 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1953 mono_domain_unlock (domain);
1954 mono_loader_unlock ();
1955 return runtime_info->domain_vtables [domain->domain_id];
1957 if (!klass->inited || mono_class_has_failure (klass)) {
1958 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1959 mono_domain_unlock (domain);
1960 mono_loader_unlock ();
1961 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
1966 /* Array types require that their element type be valid*/
1967 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1968 MonoClass *element_class = klass->element_class;
1969 if (!element_class->inited)
1970 mono_class_init (element_class);
1972 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1973 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1974 mono_class_setup_vtable (element_class);
1976 if (mono_class_has_failure (element_class)) {
1977 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1978 if (!mono_class_has_failure (klass))
1979 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
1980 mono_domain_unlock (domain);
1981 mono_loader_unlock ();
1982 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
1988 * For some classes, mono_class_init () already computed klass->vtable_size, and
1989 * that is all that is needed because of the vtable trampolines.
1991 if (!klass->vtable_size)
1992 mono_class_setup_vtable (klass);
1994 if (klass->generic_class && !klass->vtable)
1995 mono_class_check_vtable_constraints (klass, NULL);
1997 /* Initialize klass->has_finalize */
1998 mono_class_has_finalizer (klass);
2000 if (mono_class_has_failure (klass)) {
2001 mono_domain_unlock (domain);
2002 mono_loader_unlock ();
2003 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
2007 vtable_slots = klass->vtable_size;
2008 /* we add an additional vtable slot to store the pointer to static field data only when needed */
2009 class_size = mono_class_data_size (klass);
2013 if (klass->interface_offsets_count) {
2014 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
2015 mono_stats.imt_number_of_tables++;
2016 mono_stats.imt_tables_size += imt_table_bytes;
2018 imt_table_bytes = 0;
2021 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
2023 mono_stats.used_class_count++;
2024 mono_stats.class_vtable_size += vtable_size;
2026 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
2027 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2028 g_assert (!((gsize)vt & 7));
2031 vt->rank = klass->rank;
2032 vt->domain = domain;
2034 mono_class_compute_gc_descriptor (klass);
2036 * We can't use typed allocation in the non-root domains, since the
2037 * collector needs the GC descriptor stored in the vtable even after
2038 * the mempool containing the vtable is destroyed when the domain is
2039 * unloaded. An alternative might be to allocate vtables in the GC
2040 * heap, but this does not seem to work (it leads to crashes inside
2041 * libgc). If that approach is tried, two gc descriptors need to be
2042 * allocated for each class: one for the root domain, and one for all
2043 * other domains. The second descriptor should contain a bit for the
2044 * vtable field in MonoObject, since we can no longer assume the
2045 * vtable is reachable by other roots after the appdomain is unloaded.
2047 #ifdef HAVE_BOEHM_GC
2048 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
2049 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
2052 vt->gc_descr = klass->gc_descr;
2054 gc_bits = mono_gc_get_vtable_bits (klass);
2055 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2057 vt->gc_bits = gc_bits;
2060 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2061 if (klass->has_static_refs) {
2062 MonoGCDescriptor statics_gc_descr;
2064 gsize default_bitmap [4] = {0};
2067 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2068 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
2069 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2070 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
2071 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
2072 if (bitmap != default_bitmap)
2075 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
2077 vt->has_static_fields = TRUE;
2078 mono_stats.class_static_data_size += class_size;
2082 while ((field = mono_class_get_fields (klass, &iter))) {
2083 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2085 if (mono_field_is_deleted (field))
2087 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2088 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2089 if (special_static != SPECIAL_STATIC_NONE) {
2090 guint32 size, offset;
2092 gsize default_bitmap [4] = {0};
2097 if (mono_type_is_reference (field->type)) {
2098 default_bitmap [0] = 1;
2100 bitmap = default_bitmap;
2101 } else if (mono_type_is_struct (field->type)) {
2102 fclass = mono_class_from_mono_type (field->type);
2103 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2104 numbits = max_set + 1;
2106 default_bitmap [0] = 0;
2108 bitmap = default_bitmap;
2110 size = mono_type_size (field->type, &align);
2111 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2112 if (!domain->special_static_fields)
2113 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2114 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2115 if (bitmap != default_bitmap)
2118 * This marks the field as special static to speed up the
2119 * checks in mono_field_static_get/set_value ().
2125 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2126 MonoClass *fklass = mono_class_from_mono_type (field->type);
2127 const char *data = mono_field_get_data (field);
2129 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2130 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2131 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2134 if (fklass->valuetype) {
2135 memcpy (t, data, mono_class_value_size (fklass, NULL));
2137 /* it's a pointer type: add check */
2138 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2145 vt->max_interface_id = klass->max_interface_id;
2146 vt->interface_bitmap = klass->interface_bitmap;
2148 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2149 // class->name, klass->interface_offsets_count);
2151 /* Initialize vtable */
2152 if (callbacks.get_vtable_trampoline) {
2153 // This also covers the AOT case
2154 for (i = 0; i < klass->vtable_size; ++i) {
2155 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2158 mono_class_setup_vtable (klass);
2160 for (i = 0; i < klass->vtable_size; ++i) {
2163 cm = klass->vtable [i];
2165 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2166 mono_error_raise_exception (error); /* FIXME: Don't raise here */
2171 if (imt_table_bytes) {
2172 /* Now that the vtable is full, we can actually fill up the IMT */
2173 for (i = 0; i < MONO_IMT_SIZE; ++i)
2174 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2178 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2179 * re-acquire them and check if another thread has created the vtable in the meantime.
2181 /* Special case System.MonoType to avoid infinite recursion */
2182 if (klass != mono_defaults.monotype_class) {
2183 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2184 if (!is_ok (error)) {
2185 mono_domain_unlock (domain);
2186 mono_loader_unlock ();
2190 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2191 /* This is unregistered in
2192 unregister_vtable_reflection_type() in
2194 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2197 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2199 /* class_vtable_array keeps an array of created vtables
2201 g_ptr_array_add (domain->class_vtable_array, vt);
2202 /* klass->runtime_info is protected by the loader lock, both when
2203 * it it enlarged and when it is stored info.
2207 * Store the vtable in klass->runtime_info.
2208 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2210 mono_memory_barrier ();
2212 old_info = klass->runtime_info;
2213 if (old_info && old_info->max_domain >= domain->domain_id) {
2214 /* someone already created a large enough runtime info */
2215 old_info->domain_vtables [domain->domain_id] = vt;
2217 int new_size = domain->domain_id;
2219 new_size = MAX (new_size, old_info->max_domain);
2221 /* make the new size a power of two */
2223 while (new_size > i)
2226 /* this is a bounded memory retention issue: may want to
2227 * handle it differently when we'll have a rcu-like system.
2229 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2230 runtime_info->max_domain = new_size - 1;
2231 /* copy the stuff from the older info */
2233 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2235 runtime_info->domain_vtables [domain->domain_id] = vt;
2237 mono_memory_barrier ();
2238 klass->runtime_info = runtime_info;
2241 if (klass == mono_defaults.monotype_class) {
2242 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2243 if (!is_ok (error)) {
2244 mono_domain_unlock (domain);
2245 mono_loader_unlock ();
2249 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2250 /* This is unregistered in
2251 unregister_vtable_reflection_type() in
2253 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2256 mono_domain_unlock (domain);
2257 mono_loader_unlock ();
2259 /* make sure the parent is initialized */
2260 /*FIXME shouldn't this fail the current type?*/
2262 mono_class_vtable_full (domain, klass->parent, error);
2267 #ifndef DISABLE_REMOTING
2269 * mono_class_proxy_vtable:
2270 * @domain: the application domain
2271 * @remove_class: the remote class
2273 * Creates a vtable for transparent proxies. It is basically
2274 * a copy of the real vtable of the class wrapped in @remote_class,
2275 * but all function pointers invoke the remoting functions, and
2276 * vtable->klass points to the transparent proxy class, and not to @class.
2279 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2281 MONO_REQ_GC_UNSAFE_MODE;
2284 MonoVTable *vt, *pvt;
2285 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2287 GSList *extra_interfaces = NULL;
2288 MonoClass *klass = remote_class->proxy_class;
2289 gpointer *interface_offsets;
2292 size_t imt_table_bytes;
2294 #ifdef COMPRESSED_INTERFACE_BITMAP
2298 vt = mono_class_vtable (domain, klass);
2299 g_assert (vt); /*FIXME property handle failure*/
2300 max_interface_id = vt->max_interface_id;
2302 /* Calculate vtable space for extra interfaces */
2303 for (j = 0; j < remote_class->interface_count; j++) {
2304 MonoClass* iclass = remote_class->interfaces[j];
2308 /*FIXME test for interfaces with variant generic arguments*/
2309 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2310 continue; /* interface implemented by the class */
2311 if (g_slist_find (extra_interfaces, iclass))
2314 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2316 method_count = mono_class_num_methods (iclass);
2318 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2319 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2321 for (i = 0; i < ifaces->len; ++i) {
2322 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2323 /*FIXME test for interfaces with variant generic arguments*/
2324 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2325 continue; /* interface implemented by the class */
2326 if (g_slist_find (extra_interfaces, ic))
2328 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2329 method_count += mono_class_num_methods (ic);
2331 g_ptr_array_free (ifaces, TRUE);
2334 extra_interface_vtsize += method_count * sizeof (gpointer);
2335 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2338 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2339 mono_stats.imt_number_of_tables++;
2340 mono_stats.imt_tables_size += imt_table_bytes;
2342 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2344 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2346 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2347 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2348 g_assert (!((gsize)pvt & 7));
2350 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2352 pvt->klass = mono_defaults.transparent_proxy_class;
2353 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2354 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2356 /* initialize vtable */
2357 mono_class_setup_vtable (klass);
2358 for (i = 0; i < klass->vtable_size; ++i) {
2361 if ((cm = klass->vtable [i]))
2362 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2364 pvt->vtable [i] = NULL;
2367 if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2368 /* create trampolines for abstract methods */
2369 for (k = klass; k; k = k->parent) {
2371 gpointer iter = NULL;
2372 while ((m = mono_class_get_methods (k, &iter)))
2373 if (!pvt->vtable [m->slot])
2374 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2378 pvt->max_interface_id = max_interface_id;
2379 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2380 #ifdef COMPRESSED_INTERFACE_BITMAP
2381 bitmap = (uint8_t *)g_malloc0 (bsize);
2383 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2386 for (i = 0; i < klass->interface_offsets_count; ++i) {
2387 int interface_id = klass->interfaces_packed [i]->interface_id;
2388 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2391 if (extra_interfaces) {
2392 int slot = klass->vtable_size;
2398 /* Create trampolines for the methods of the interfaces */
2399 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2400 interf = (MonoClass *)list_item->data;
2402 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2406 while ((cm = mono_class_get_methods (interf, &iter)))
2407 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2409 slot += mono_class_num_methods (interf);
2413 /* Now that the vtable is full, we can actually fill up the IMT */
2414 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2415 if (extra_interfaces) {
2416 g_slist_free (extra_interfaces);
2419 #ifdef COMPRESSED_INTERFACE_BITMAP
2420 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2421 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2422 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2425 pvt->interface_bitmap = bitmap;
2430 #endif /* DISABLE_REMOTING */
2433 * mono_class_field_is_special_static:
2435 * Returns whether @field is a thread/context static field.
2438 mono_class_field_is_special_static (MonoClassField *field)
2440 MONO_REQ_GC_NEUTRAL_MODE
2442 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2444 if (mono_field_is_deleted (field))
2446 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2447 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2454 * mono_class_field_get_special_static_type:
2455 * @field: The MonoClassField describing the field.
2457 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2458 * SPECIAL_STATIC_NONE otherwise.
2461 mono_class_field_get_special_static_type (MonoClassField *field)
2463 MONO_REQ_GC_NEUTRAL_MODE
2465 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2466 return SPECIAL_STATIC_NONE;
2467 if (mono_field_is_deleted (field))
2468 return SPECIAL_STATIC_NONE;
2469 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2470 return field_is_special_static (field->parent, field);
2471 return SPECIAL_STATIC_NONE;
2475 * mono_class_has_special_static_fields:
2477 * Returns whenever @klass has any thread/context static fields.
2480 mono_class_has_special_static_fields (MonoClass *klass)
2482 MONO_REQ_GC_NEUTRAL_MODE
2484 MonoClassField *field;
2488 while ((field = mono_class_get_fields (klass, &iter))) {
2489 g_assert (field->parent == klass);
2490 if (mono_class_field_is_special_static (field))
2497 #ifndef DISABLE_REMOTING
2499 * create_remote_class_key:
2500 * Creates an array of pointers that can be used as a hash key for a remote class.
2501 * The first element of the array is the number of pointers.
2504 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2506 MONO_REQ_GC_NEUTRAL_MODE;
2511 if (remote_class == NULL) {
2512 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2513 key = (void **)g_malloc (sizeof(gpointer) * 3);
2514 key [0] = GINT_TO_POINTER (2);
2515 key [1] = mono_defaults.marshalbyrefobject_class;
2516 key [2] = extra_class;
2518 key = (void **)g_malloc (sizeof(gpointer) * 2);
2519 key [0] = GINT_TO_POINTER (1);
2520 key [1] = extra_class;
2523 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2524 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2525 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2526 key [1] = remote_class->proxy_class;
2528 // Keep the list of interfaces sorted
2529 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2530 if (extra_class && remote_class->interfaces [i] > extra_class) {
2531 key [j++] = extra_class;
2534 key [j] = remote_class->interfaces [i];
2537 key [j] = extra_class;
2539 // Replace the old class. The interface list is the same
2540 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2541 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2542 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2543 for (i = 0; i < remote_class->interface_count; i++)
2544 key [2 + i] = remote_class->interfaces [i];
2552 * copy_remote_class_key:
2554 * Make a copy of KEY in the domain and return the copy.
2557 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2559 MONO_REQ_GC_NEUTRAL_MODE
2561 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2562 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2564 memcpy (mp_key, key, key_size);
2570 * mono_remote_class:
2571 * @domain: the application domain
2572 * @class_name: name of the remote class
2574 * Creates and initializes a MonoRemoteClass object for a remote type.
2576 * Can raise an exception on failure.
2579 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2581 MONO_REQ_GC_UNSAFE_MODE;
2584 MonoRemoteClass *rc;
2585 gpointer* key, *mp_key;
2588 key = create_remote_class_key (NULL, proxy_class);
2590 mono_domain_lock (domain);
2591 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2595 mono_domain_unlock (domain);
2599 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2600 if (!mono_error_ok (&error)) {
2602 mono_domain_unlock (domain);
2603 mono_error_raise_exception (&error);
2606 mp_key = copy_remote_class_key (domain, key);
2610 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2611 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2612 rc->interface_count = 1;
2613 rc->interfaces [0] = proxy_class;
2614 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2616 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2617 rc->interface_count = 0;
2618 rc->proxy_class = proxy_class;
2621 rc->default_vtable = NULL;
2622 rc->xdomain_vtable = NULL;
2623 rc->proxy_class_name = name;
2624 #ifndef DISABLE_PERFCOUNTERS
2625 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2628 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2630 mono_domain_unlock (domain);
2635 * clone_remote_class:
2636 * Creates a copy of the remote_class, adding the provided class or interface
2638 static MonoRemoteClass*
2639 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2641 MONO_REQ_GC_NEUTRAL_MODE;
2643 MonoRemoteClass *rc;
2644 gpointer* key, *mp_key;
2646 key = create_remote_class_key (remote_class, extra_class);
2647 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2653 mp_key = copy_remote_class_key (domain, key);
2657 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2659 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2660 rc->proxy_class = remote_class->proxy_class;
2661 rc->interface_count = remote_class->interface_count + 1;
2663 // Keep the list of interfaces sorted, since the hash key of
2664 // the remote class depends on this
2665 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2666 if (remote_class->interfaces [i] > extra_class && i == j)
2667 rc->interfaces [j++] = extra_class;
2668 rc->interfaces [j] = remote_class->interfaces [i];
2671 rc->interfaces [j] = extra_class;
2673 // Replace the old class. The interface array is the same
2674 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2675 rc->proxy_class = extra_class;
2676 rc->interface_count = remote_class->interface_count;
2677 if (rc->interface_count > 0)
2678 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2681 rc->default_vtable = NULL;
2682 rc->xdomain_vtable = NULL;
2683 rc->proxy_class_name = remote_class->proxy_class_name;
2685 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2691 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2693 MONO_REQ_GC_UNSAFE_MODE;
2695 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2696 mono_domain_lock (domain);
2697 if (rp->target_domain_id != -1) {
2698 if (remote_class->xdomain_vtable == NULL)
2699 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2700 mono_domain_unlock (domain);
2701 mono_loader_unlock ();
2702 return remote_class->xdomain_vtable;
2704 if (remote_class->default_vtable == NULL) {
2707 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2708 klass = mono_class_from_mono_type (type);
2710 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)))
2711 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2714 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2717 mono_domain_unlock (domain);
2718 mono_loader_unlock ();
2719 return remote_class->default_vtable;
2723 * mono_upgrade_remote_class:
2724 * @domain: the application domain
2725 * @tproxy: the proxy whose remote class has to be upgraded.
2726 * @klass: class to which the remote class can be casted.
2728 * Updates the vtable of the remote class by adding the necessary method slots
2729 * and interface offsets so it can be safely casted to klass. klass can be a
2730 * class or an interface.
2733 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2735 MONO_REQ_GC_UNSAFE_MODE;
2737 MonoTransparentProxy *tproxy;
2738 MonoRemoteClass *remote_class;
2739 gboolean redo_vtable;
2741 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2742 mono_domain_lock (domain);
2744 tproxy = (MonoTransparentProxy*) proxy_object;
2745 remote_class = tproxy->remote_class;
2747 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2750 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2751 if (remote_class->interfaces [i] == klass)
2752 redo_vtable = FALSE;
2755 redo_vtable = (remote_class->proxy_class != klass);
2759 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2760 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2763 mono_domain_unlock (domain);
2764 mono_loader_unlock ();
2766 #endif /* DISABLE_REMOTING */
2770 * mono_object_get_virtual_method:
2771 * @obj: object to operate on.
2774 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2775 * the instance of a callvirt of method.
2778 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2780 MONO_REQ_GC_UNSAFE_MODE;
2783 MonoMethod **vtable;
2784 gboolean is_proxy = FALSE;
2785 MonoMethod *res = NULL;
2787 klass = mono_object_class (obj);
2788 #ifndef DISABLE_REMOTING
2789 if (klass == mono_defaults.transparent_proxy_class) {
2790 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2795 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2798 mono_class_setup_vtable (klass);
2799 vtable = klass->vtable;
2801 if (method->slot == -1) {
2802 /* method->slot might not be set for instances of generic methods */
2803 if (method->is_inflated) {
2804 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2805 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2808 g_assert_not_reached ();
2812 /* check method->slot is a valid index: perform isinstance? */
2813 if (method->slot != -1) {
2814 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2816 gboolean variance_used = FALSE;
2817 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2818 g_assert (iface_offset > 0);
2819 res = vtable [iface_offset + method->slot];
2822 res = vtable [method->slot];
2826 #ifndef DISABLE_REMOTING
2828 /* It may be an interface, abstract class method or generic method */
2829 if (!res || mono_method_signature (res)->generic_param_count)
2832 /* generic methods demand invoke_with_check */
2833 if (mono_method_signature (res)->generic_param_count)
2834 res = mono_marshal_get_remoting_invoke_with_check (res);
2837 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2838 res = mono_cominterop_get_invoke (res);
2841 res = mono_marshal_get_remoting_invoke (res);
2846 if (method->is_inflated) {
2848 /* Have to inflate the result */
2849 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2850 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2860 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2862 MONO_REQ_GC_UNSAFE_MODE;
2864 MonoObject *result = NULL;
2866 g_assert (callbacks.runtime_invoke);
2868 mono_error_init (error);
2870 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2871 mono_profiler_method_start_invoke (method);
2873 MONO_PREPARE_RESET_BLOCKING;
2875 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2877 MONO_FINISH_RESET_BLOCKING;
2879 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2880 mono_profiler_method_end_invoke (method);
2882 if (!mono_error_ok (error))
2889 * mono_runtime_invoke:
2890 * @method: method to invoke
2891 * @obJ: object instance
2892 * @params: arguments to the method
2893 * @exc: exception information.
2895 * Invokes the method represented by @method on the object @obj.
2897 * obj is the 'this' pointer, it should be NULL for static
2898 * methods, a MonoObject* for object instances and a pointer to
2899 * the value type for value types.
2901 * The params array contains the arguments to the method with the
2902 * same convention: MonoObject* pointers for object instances and
2903 * pointers to the value type otherwise.
2905 * From unmanaged code you'll usually use the
2906 * mono_runtime_invoke() variant.
2908 * Note that this function doesn't handle virtual methods for
2909 * you, it will exec the exact method you pass: we still need to
2910 * expose a function to lookup the derived class implementation
2911 * of a virtual method (there are examples of this in the code,
2914 * You can pass NULL as the exc argument if you don't want to
2915 * catch exceptions, otherwise, *exc will be set to the exception
2916 * thrown, if any. if an exception is thrown, you can't use the
2917 * MonoObject* result from the function.
2919 * If the method returns a value type, it is boxed in an object
2923 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2928 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2929 if (*exc == NULL && !mono_error_ok(&error)) {
2930 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2932 mono_error_cleanup (&error);
2934 res = mono_runtime_invoke_checked (method, obj, params, &error);
2935 mono_error_raise_exception (&error);
2941 * mono_runtime_try_invoke:
2942 * @method: method to invoke
2943 * @obJ: object instance
2944 * @params: arguments to the method
2945 * @exc: exception information.
2946 * @error: set on error
2948 * Invokes the method represented by @method on the object @obj.
2950 * obj is the 'this' pointer, it should be NULL for static
2951 * methods, a MonoObject* for object instances and a pointer to
2952 * the value type for value types.
2954 * The params array contains the arguments to the method with the
2955 * same convention: MonoObject* pointers for object instances and
2956 * pointers to the value type otherwise.
2958 * From unmanaged code you'll usually use the
2959 * mono_runtime_invoke() variant.
2961 * Note that this function doesn't handle virtual methods for
2962 * you, it will exec the exact method you pass: we still need to
2963 * expose a function to lookup the derived class implementation
2964 * of a virtual method (there are examples of this in the code,
2967 * For this function, you must not pass NULL as the exc argument if
2968 * you don't want to catch exceptions, use
2969 * mono_runtime_invoke_checked(). If an exception is thrown, you
2970 * can't use the MonoObject* result from the function.
2972 * If this method cannot be invoked, @error will be set and @exc and
2973 * the return value must not be used.
2975 * If the method returns a value type, it is boxed in an object
2979 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2981 MONO_REQ_GC_UNSAFE_MODE;
2983 g_assert (exc != NULL);
2985 if (mono_runtime_get_no_exec ())
2986 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2988 return do_runtime_invoke (method, obj, params, exc, error);
2992 * mono_runtime_invoke_checked:
2993 * @method: method to invoke
2994 * @obJ: object instance
2995 * @params: arguments to the method
2996 * @error: set on error
2998 * Invokes the method represented by @method on the object @obj.
3000 * obj is the 'this' pointer, it should be NULL for static
3001 * methods, a MonoObject* for object instances and a pointer to
3002 * the value type for value types.
3004 * The params array contains the arguments to the method with the
3005 * same convention: MonoObject* pointers for object instances and
3006 * pointers to the value type otherwise.
3008 * From unmanaged code you'll usually use the
3009 * mono_runtime_invoke() variant.
3011 * Note that this function doesn't handle virtual methods for
3012 * you, it will exec the exact method you pass: we still need to
3013 * expose a function to lookup the derived class implementation
3014 * of a virtual method (there are examples of this in the code,
3017 * If an exception is thrown, you can't use the MonoObject* result
3018 * from the function.
3020 * If this method cannot be invoked, @error will be set. If the
3021 * method throws an exception (and we're in coop mode) the exception
3022 * will be set in @error.
3024 * If the method returns a value type, it is boxed in an object
3028 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3030 MONO_REQ_GC_UNSAFE_MODE;
3032 if (mono_runtime_get_no_exec ())
3033 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3035 return do_runtime_invoke (method, obj, params, NULL, error);
3039 * mono_method_get_unmanaged_thunk:
3040 * @method: method to generate a thunk for.
3042 * Returns an unmanaged->managed thunk that can be used to call
3043 * a managed method directly from C.
3045 * The thunk's C signature closely matches the managed signature:
3047 * C#: public bool Equals (object obj);
3048 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3049 * MonoObject*, MonoException**);
3051 * The 1st ("this") parameter must not be used with static methods:
3053 * C#: public static bool ReferenceEquals (object a, object b);
3054 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3057 * The last argument must be a non-null pointer of a MonoException* pointer.
3058 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3059 * exception has been thrown in managed code. Otherwise it will point
3060 * to the MonoException* caught by the thunk. In this case, the result of
3061 * the thunk is undefined:
3063 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3064 * MonoException *ex = NULL;
3065 * Equals func = mono_method_get_unmanaged_thunk (method);
3066 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3068 * // handle exception
3071 * The calling convention of the thunk matches the platform's default
3072 * convention. This means that under Windows, C declarations must
3073 * contain the __stdcall attribute:
3075 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3076 * MonoObject*, MonoException**);
3080 * Value type arguments and return values are treated as they were objects:
3082 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3083 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3085 * Arguments must be properly boxed upon trunk's invocation, while return
3086 * values must be unboxed.
3089 mono_method_get_unmanaged_thunk (MonoMethod *method)
3091 MONO_REQ_GC_NEUTRAL_MODE;
3092 MONO_REQ_API_ENTRYPOINT;
3096 MONO_PREPARE_RESET_BLOCKING;
3097 method = mono_marshal_get_thunk_invoke_wrapper (method);
3098 res = mono_compile_method (method);
3099 MONO_FINISH_RESET_BLOCKING;
3105 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3107 MONO_REQ_GC_UNSAFE_MODE;
3111 /* object fields cannot be byref, so we don't need a
3113 gpointer *p = (gpointer*)dest;
3120 case MONO_TYPE_BOOLEAN:
3122 case MONO_TYPE_U1: {
3123 guint8 *p = (guint8*)dest;
3124 *p = value ? *(guint8*)value : 0;
3129 case MONO_TYPE_CHAR: {
3130 guint16 *p = (guint16*)dest;
3131 *p = value ? *(guint16*)value : 0;
3134 #if SIZEOF_VOID_P == 4
3139 case MONO_TYPE_U4: {
3140 gint32 *p = (gint32*)dest;
3141 *p = value ? *(gint32*)value : 0;
3144 #if SIZEOF_VOID_P == 8
3149 case MONO_TYPE_U8: {
3150 gint64 *p = (gint64*)dest;
3151 *p = value ? *(gint64*)value : 0;
3154 case MONO_TYPE_R4: {
3155 float *p = (float*)dest;
3156 *p = value ? *(float*)value : 0;
3159 case MONO_TYPE_R8: {
3160 double *p = (double*)dest;
3161 *p = value ? *(double*)value : 0;
3164 case MONO_TYPE_STRING:
3165 case MONO_TYPE_SZARRAY:
3166 case MONO_TYPE_CLASS:
3167 case MONO_TYPE_OBJECT:
3168 case MONO_TYPE_ARRAY:
3169 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3171 case MONO_TYPE_FNPTR:
3172 case MONO_TYPE_PTR: {
3173 gpointer *p = (gpointer*)dest;
3174 *p = deref_pointer? *(gpointer*)value: value;
3177 case MONO_TYPE_VALUETYPE:
3178 /* note that 't' and 'type->type' can be different */
3179 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3180 t = mono_class_enum_basetype (type->data.klass)->type;
3183 MonoClass *klass = mono_class_from_mono_type (type);
3184 int size = mono_class_value_size (klass, NULL);
3186 mono_gc_bzero_atomic (dest, size);
3188 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3191 case MONO_TYPE_GENERICINST:
3192 t = type->data.generic_class->container_class->byval_arg.type;
3195 g_error ("got type %x", type->type);
3200 * mono_field_set_value:
3201 * @obj: Instance object
3202 * @field: MonoClassField describing the field to set
3203 * @value: The value to be set
3205 * Sets the value of the field described by @field in the object instance @obj
3206 * to the value passed in @value. This method should only be used for instance
3207 * fields. For static fields, use mono_field_static_set_value.
3209 * The value must be on the native format of the field type.
3212 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3214 MONO_REQ_GC_UNSAFE_MODE;
3218 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3220 dest = (char*)obj + field->offset;
3221 mono_copy_value (field->type, dest, value, FALSE);
3225 * mono_field_static_set_value:
3226 * @field: MonoClassField describing the field to set
3227 * @value: The value to be set
3229 * Sets the value of the static field described by @field
3230 * to the value passed in @value.
3232 * The value must be on the native format of the field type.
3235 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3237 MONO_REQ_GC_UNSAFE_MODE;
3241 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3242 /* you cant set a constant! */
3243 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3245 if (field->offset == -1) {
3246 /* Special static */
3249 mono_domain_lock (vt->domain);
3250 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3251 mono_domain_unlock (vt->domain);
3252 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3254 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3256 mono_copy_value (field->type, dest, value, FALSE);
3260 * mono_vtable_get_static_field_data:
3262 * Internal use function: return a pointer to the memory holding the static fields
3263 * for a class or NULL if there are no static fields.
3264 * This is exported only for use by the debugger.
3267 mono_vtable_get_static_field_data (MonoVTable *vt)
3269 MONO_REQ_GC_NEUTRAL_MODE
3271 if (!vt->has_static_fields)
3273 return vt->vtable [vt->klass->vtable_size];
3277 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3279 MONO_REQ_GC_UNSAFE_MODE;
3283 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3284 if (field->offset == -1) {
3285 /* Special static */
3288 mono_domain_lock (vt->domain);
3289 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3290 mono_domain_unlock (vt->domain);
3291 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3293 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3296 src = (guint8*)obj + field->offset;
3303 * mono_field_get_value:
3304 * @obj: Object instance
3305 * @field: MonoClassField describing the field to fetch information from
3306 * @value: pointer to the location where the value will be stored
3308 * Use this routine to get the value of the field @field in the object
3311 * The pointer provided by value must be of the field type, for reference
3312 * types this is a MonoObject*, for value types its the actual pointer to
3317 * mono_field_get_value (obj, int_field, &i);
3320 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3322 MONO_REQ_GC_UNSAFE_MODE;
3328 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3330 src = (char*)obj + field->offset;
3331 mono_copy_value (field->type, value, src, TRUE);
3335 * mono_field_get_value_object:
3336 * @domain: domain where the object will be created (if boxing)
3337 * @field: MonoClassField describing the field to fetch information from
3338 * @obj: The object instance for the field.
3340 * Returns: a new MonoObject with the value from the given field. If the
3341 * field represents a value type, the value is boxed.
3345 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3347 MONO_REQ_GC_UNSAFE_MODE;
3352 MonoVTable *vtable = NULL;
3354 gboolean is_static = FALSE;
3355 gboolean is_ref = FALSE;
3356 gboolean is_literal = FALSE;
3357 gboolean is_ptr = FALSE;
3358 MonoType *type = mono_field_get_type_checked (field, &error);
3360 if (!mono_error_ok (&error))
3361 mono_error_raise_exception (&error); /* FIXME don't raise here */
3363 switch (type->type) {
3364 case MONO_TYPE_STRING:
3365 case MONO_TYPE_OBJECT:
3366 case MONO_TYPE_CLASS:
3367 case MONO_TYPE_ARRAY:
3368 case MONO_TYPE_SZARRAY:
3373 case MONO_TYPE_BOOLEAN:
3376 case MONO_TYPE_CHAR:
3385 case MONO_TYPE_VALUETYPE:
3386 is_ref = type->byref;
3388 case MONO_TYPE_GENERICINST:
3389 is_ref = !mono_type_generic_inst_is_valuetype (type);
3395 g_error ("type 0x%x not handled in "
3396 "mono_field_get_value_object", type->type);
3400 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3403 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3407 vtable = mono_class_vtable_full (domain, field->parent, &error);
3408 mono_error_raise_exception (&error); /* FIXME don't raise here */
3410 if (!vtable->initialized) {
3411 mono_runtime_class_init_full (vtable, &error);
3412 mono_error_raise_exception (&error); /* FIXME don't raise here */
3421 get_default_field_value (domain, field, &o);
3422 } else if (is_static) {
3423 mono_field_static_get_value (vtable, field, &o);
3425 mono_field_get_value (obj, field, &o);
3431 static MonoMethod *m;
3437 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3438 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3444 get_default_field_value (domain, field, v);
3445 } else if (is_static) {
3446 mono_field_static_get_value (vtable, field, v);
3448 mono_field_get_value (obj, field, v);
3451 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3452 args [0] = ptr ? *ptr : NULL;
3453 args [1] = mono_type_get_object_checked (mono_domain_get (), type, &error);
3454 mono_error_raise_exception (&error); /* FIXME don't raise here */
3456 o = mono_runtime_invoke_checked (m, NULL, args, &error);
3457 mono_error_raise_exception (&error); /* FIXME don't raise here */
3462 /* boxed value type */
3463 klass = mono_class_from_mono_type (type);
3465 if (mono_class_is_nullable (klass))
3466 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3468 o = mono_object_new_checked (domain, klass, &error);
3469 mono_error_raise_exception (&error); /* FIXME don't raise here */
3470 v = ((gchar *) o) + sizeof (MonoObject);
3473 get_default_field_value (domain, field, v);
3474 } else if (is_static) {
3475 mono_field_static_get_value (vtable, field, v);
3477 mono_field_get_value (obj, field, v);
3484 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3486 MONO_REQ_GC_UNSAFE_MODE;
3489 const char *p = blob;
3490 mono_metadata_decode_blob_size (p, &p);
3493 case MONO_TYPE_BOOLEAN:
3496 *(guint8 *) value = *p;
3498 case MONO_TYPE_CHAR:
3501 *(guint16*) value = read16 (p);
3505 *(guint32*) value = read32 (p);
3509 *(guint64*) value = read64 (p);
3512 readr4 (p, (float*) value);
3515 readr8 (p, (double*) value);
3517 case MONO_TYPE_STRING:
3518 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3520 case MONO_TYPE_CLASS:
3521 *(gpointer*) value = NULL;
3525 g_warning ("type 0x%02x should not be in constant table", type);
3531 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3533 MONO_REQ_GC_NEUTRAL_MODE;
3535 MonoTypeEnum def_type;
3538 data = mono_class_get_field_default_value (field, &def_type);
3539 mono_get_constant_value_from_blob (domain, def_type, data, value);
3543 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3545 MONO_REQ_GC_UNSAFE_MODE;
3549 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3551 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3552 get_default_field_value (vt->domain, field, value);
3556 if (field->offset == -1) {
3557 /* Special static */
3558 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3559 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3561 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3563 mono_copy_value (field->type, value, src, TRUE);
3567 * mono_field_static_get_value:
3568 * @vt: vtable to the object
3569 * @field: MonoClassField describing the field to fetch information from
3570 * @value: where the value is returned
3572 * Use this routine to get the value of the static field @field value.
3574 * The pointer provided by value must be of the field type, for reference
3575 * types this is a MonoObject*, for value types its the actual pointer to
3580 * mono_field_static_get_value (vt, int_field, &i);
3583 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3585 MONO_REQ_GC_NEUTRAL_MODE;
3587 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3591 * mono_property_set_value:
3592 * @prop: MonoProperty to set
3593 * @obj: instance object on which to act
3594 * @params: parameters to pass to the propery
3595 * @exc: optional exception
3597 * Invokes the property's set method with the given arguments on the
3598 * object instance obj (or NULL for static properties).
3600 * You can pass NULL as the exc argument if you don't want to
3601 * catch exceptions, otherwise, *exc will be set to the exception
3602 * thrown, if any. if an exception is thrown, you can't use the
3603 * MonoObject* result from the function.
3606 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3608 MONO_REQ_GC_UNSAFE_MODE;
3611 do_runtime_invoke (prop->set, obj, params, exc, &error);
3612 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3613 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3615 mono_error_raise_exception (&error); /* FIXME don't raise here */
3620 * mono_property_get_value:
3621 * @prop: MonoProperty to fetch
3622 * @obj: instance object on which to act
3623 * @params: parameters to pass to the propery
3624 * @exc: optional exception
3626 * Invokes the property's get method with the given arguments on the
3627 * object instance obj (or NULL for static properties).
3629 * You can pass NULL as the exc argument if you don't want to
3630 * catch exceptions, otherwise, *exc will be set to the exception
3631 * thrown, if any. if an exception is thrown, you can't use the
3632 * MonoObject* result from the function.
3634 * Returns: the value from invoking the get method on the property.
3637 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3639 MONO_REQ_GC_UNSAFE_MODE;
3642 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3643 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3644 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3646 mono_error_raise_exception (&error); /* FIXME don't raise here */
3653 * mono_nullable_init:
3654 * @buf: The nullable structure to initialize.
3655 * @value: the value to initialize from
3656 * @klass: the type for the object
3658 * Initialize the nullable structure pointed to by @buf from @value which
3659 * should be a boxed value type. The size of @buf should be able to hold
3660 * as much data as the @klass->instance_size (which is the number of bytes
3661 * that will be copies).
3663 * Since Nullables have variable structure, we can not define a C
3664 * structure for them.
3667 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3669 MONO_REQ_GC_UNSAFE_MODE;
3671 MonoClass *param_class = klass->cast_class;
3673 mono_class_setup_fields_locking (klass);
3674 g_assert (klass->fields_inited);
3676 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3677 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3679 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3681 if (param_class->has_references)
3682 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3684 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3686 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3691 * mono_nullable_box:
3692 * @buf: The buffer representing the data to be boxed
3693 * @klass: the type to box it as.
3695 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3699 mono_nullable_box (guint8 *buf, MonoClass *klass)
3701 MONO_REQ_GC_UNSAFE_MODE;
3705 MonoClass *param_class = klass->cast_class;
3707 mono_class_setup_fields_locking (klass);
3708 g_assert (klass->fields_inited);
3710 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3711 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3713 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3714 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, &error);
3715 mono_error_raise_exception (&error); /* FIXME don't raise here */
3716 if (param_class->has_references)
3717 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3719 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3727 * mono_get_delegate_invoke:
3728 * @klass: The delegate class
3730 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3733 mono_get_delegate_invoke (MonoClass *klass)
3735 MONO_REQ_GC_NEUTRAL_MODE;
3739 /* This is called at runtime, so avoid the slower search in metadata */
3740 mono_class_setup_methods (klass);
3741 if (mono_class_has_failure (klass))
3743 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3748 * mono_get_delegate_begin_invoke:
3749 * @klass: The delegate class
3751 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3754 mono_get_delegate_begin_invoke (MonoClass *klass)
3756 MONO_REQ_GC_NEUTRAL_MODE;
3760 /* This is called at runtime, so avoid the slower search in metadata */
3761 mono_class_setup_methods (klass);
3762 if (mono_class_has_failure (klass))
3764 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3769 * mono_get_delegate_end_invoke:
3770 * @klass: The delegate class
3772 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3775 mono_get_delegate_end_invoke (MonoClass *klass)
3777 MONO_REQ_GC_NEUTRAL_MODE;
3781 /* This is called at runtime, so avoid the slower search in metadata */
3782 mono_class_setup_methods (klass);
3783 if (mono_class_has_failure (klass))
3785 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3790 * mono_runtime_delegate_invoke:
3791 * @delegate: pointer to a delegate object.
3792 * @params: parameters for the delegate.
3793 * @exc: Pointer to the exception result.
3795 * Invokes the delegate method @delegate with the parameters provided.
3797 * You can pass NULL as the exc argument if you don't want to
3798 * catch exceptions, otherwise, *exc will be set to the exception
3799 * thrown, if any. if an exception is thrown, you can't use the
3800 * MonoObject* result from the function.
3803 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3805 MONO_REQ_GC_UNSAFE_MODE;
3809 MonoClass *klass = delegate->vtable->klass;
3812 im = mono_get_delegate_invoke (klass);
3814 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3817 o = mono_runtime_try_invoke (im, delegate, params, exc, &error);
3818 if (*exc == NULL && !mono_error_ok (&error))
3819 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3821 mono_error_cleanup (&error);
3823 o = mono_runtime_invoke_checked (im, delegate, params, &error);
3824 mono_error_raise_exception (&error); /* FIXME don't raise here */
3830 static char **main_args = NULL;
3831 static int num_main_args = 0;
3834 * mono_runtime_get_main_args:
3836 * Returns: a MonoArray with the arguments passed to the main program
3839 mono_runtime_get_main_args (void)
3841 MONO_REQ_GC_UNSAFE_MODE;
3845 MonoDomain *domain = mono_domain_get ();
3847 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3849 for (i = 0; i < num_main_args; ++i)
3850 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3856 free_main_args (void)
3858 MONO_REQ_GC_NEUTRAL_MODE;
3862 for (i = 0; i < num_main_args; ++i)
3863 g_free (main_args [i]);
3870 * mono_runtime_set_main_args:
3871 * @argc: number of arguments from the command line
3872 * @argv: array of strings from the command line
3874 * Set the command line arguments from an embedding application that doesn't otherwise call
3875 * mono_runtime_run_main ().
3878 mono_runtime_set_main_args (int argc, char* argv[])
3880 MONO_REQ_GC_NEUTRAL_MODE;
3885 main_args = g_new0 (char*, argc);
3886 num_main_args = argc;
3888 for (i = 0; i < argc; ++i) {
3891 utf8_arg = mono_utf8_from_external (argv[i]);
3892 if (utf8_arg == NULL) {
3893 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3894 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3898 main_args [i] = utf8_arg;
3905 * mono_runtime_run_main:
3906 * @method: the method to start the application with (usually Main)
3907 * @argc: number of arguments from the command line
3908 * @argv: array of strings from the command line
3909 * @exc: excetption results
3911 * Execute a standard Main() method (argc/argv contains the
3912 * executable name). This method also sets the command line argument value
3913 * needed by System.Environment.
3918 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3921 MONO_REQ_GC_UNSAFE_MODE;
3924 MonoArray *args = NULL;
3925 MonoDomain *domain = mono_domain_get ();
3926 gchar *utf8_fullpath;
3927 MonoMethodSignature *sig;
3929 g_assert (method != NULL);
3931 mono_thread_set_main (mono_thread_current ());
3933 main_args = g_new0 (char*, argc);
3934 num_main_args = argc;
3936 if (!g_path_is_absolute (argv [0])) {
3937 gchar *basename = g_path_get_basename (argv [0]);
3938 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3942 utf8_fullpath = mono_utf8_from_external (fullpath);
3943 if(utf8_fullpath == NULL) {
3944 /* Printing the arg text will cause glib to
3945 * whinge about "Invalid UTF-8", but at least
3946 * its relevant, and shows the problem text
3949 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3950 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3957 utf8_fullpath = mono_utf8_from_external (argv[0]);
3958 if(utf8_fullpath == NULL) {
3959 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3960 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3965 main_args [0] = utf8_fullpath;
3967 for (i = 1; i < argc; ++i) {
3970 utf8_arg=mono_utf8_from_external (argv[i]);
3971 if(utf8_arg==NULL) {
3972 /* Ditto the comment about Invalid UTF-8 here */
3973 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3974 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3978 main_args [i] = utf8_arg;
3983 sig = mono_method_signature (method);
3985 g_print ("Unable to load Main method.\n");
3989 if (sig->param_count) {
3990 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3991 for (i = 0; i < argc; ++i) {
3992 /* The encodings should all work, given that
3993 * we've checked all these args for the
3996 gchar *str = mono_utf8_from_external (argv [i]);
3997 MonoString *arg = mono_string_new (domain, str);
3998 mono_array_setref (args, i, arg);
4002 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
4005 mono_assembly_set_main (method->klass->image->assembly);
4007 return mono_runtime_exec_main (method, args, exc);
4011 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4013 static MonoMethod *serialize_method;
4019 if (!serialize_method) {
4020 MonoClass *klass = mono_class_get_remoting_services_class ();
4021 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4024 if (!serialize_method) {
4029 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4034 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4035 if (*exc == NULL && !mono_error_ok (&error))
4036 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4038 mono_error_cleanup (&error);
4047 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4049 MONO_REQ_GC_UNSAFE_MODE;
4051 static MonoMethod *deserialize_method;
4057 if (!deserialize_method) {
4058 MonoClass *klass = mono_class_get_remoting_services_class ();
4059 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4061 if (!deserialize_method) {
4069 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4070 if (*exc == NULL && !mono_error_ok (&error))
4071 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4073 mono_error_cleanup (&error);
4081 #ifndef DISABLE_REMOTING
4083 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
4085 MONO_REQ_GC_UNSAFE_MODE;
4087 static MonoMethod *get_proxy_method;
4090 MonoDomain *domain = mono_domain_get ();
4091 MonoRealProxy *real_proxy;
4092 MonoReflectionType *reflection_type;
4093 MonoTransparentProxy *transparent_proxy;
4095 if (!get_proxy_method)
4096 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4098 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4100 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, &error);
4101 mono_error_raise_exception (&error); /* FIXME don't raise here */
4102 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, &error);
4103 mono_error_raise_exception (&error); /* FIXME don't raise here */
4105 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4106 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4110 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, exc, &error);
4111 if (*exc == NULL && !mono_error_ok (&error))
4112 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME change make_transparent_proxy outarg to MonoError */
4114 mono_error_cleanup (&error);
4118 return (MonoObject*) transparent_proxy;
4120 #endif /* DISABLE_REMOTING */
4123 * mono_object_xdomain_representation
4125 * @target_domain: a domain
4126 * @exc: pointer to a MonoObject*
4128 * Creates a representation of obj in the domain target_domain. This
4129 * is either a copy of obj arrived through via serialization and
4130 * deserialization or a proxy, depending on whether the object is
4131 * serializable or marshal by ref. obj must not be in target_domain.
4133 * If the object cannot be represented in target_domain, NULL is
4134 * returned and *exc is set to an appropriate exception.
4137 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
4139 MONO_REQ_GC_UNSAFE_MODE;
4141 MonoObject *deserialized = NULL;
4142 gboolean failure = FALSE;
4144 g_assert (exc != NULL);
4147 #ifndef DISABLE_REMOTING
4148 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4149 deserialized = make_transparent_proxy (obj, &failure, exc);
4154 MonoDomain *domain = mono_domain_get ();
4155 MonoObject *serialized;
4157 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4158 serialized = serialize_object (obj, &failure, exc);
4159 mono_domain_set_internal_with_options (target_domain, FALSE);
4161 deserialized = deserialize_object (serialized, &failure, exc);
4162 if (domain != target_domain)
4163 mono_domain_set_internal_with_options (domain, FALSE);
4166 return deserialized;
4169 /* Used in call_unhandled_exception_delegate */
4171 create_unhandled_exception_eventargs (MonoObject *exc)
4173 MONO_REQ_GC_UNSAFE_MODE;
4178 MonoMethod *method = NULL;
4179 MonoBoolean is_terminating = TRUE;
4182 klass = mono_class_get_unhandled_exception_event_args_class ();
4183 mono_class_init (klass);
4185 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4186 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4190 args [1] = &is_terminating;
4192 obj = mono_object_new_checked (mono_domain_get (), klass, &error);
4193 mono_error_raise_exception (&error); /* FIXME don't raise here */
4195 mono_runtime_invoke_checked (method, obj, args, &error);
4196 mono_error_raise_exception (&error); /* FIXME don't raise here */
4201 /* Used in mono_unhandled_exception */
4203 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4204 MONO_REQ_GC_UNSAFE_MODE;
4206 MonoObject *e = NULL;
4208 MonoDomain *current_domain = mono_domain_get ();
4210 if (domain != current_domain)
4211 mono_domain_set_internal_with_options (domain, FALSE);
4213 g_assert (domain == mono_object_domain (domain->domain));
4215 if (mono_object_domain (exc) != domain) {
4216 MonoObject *serialization_exc;
4218 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
4220 if (serialization_exc) {
4222 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
4225 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4226 "System.Runtime.Serialization", "SerializationException",
4227 "Could not serialize unhandled exception.");
4231 g_assert (mono_object_domain (exc) == domain);
4233 pa [0] = domain->domain;
4234 pa [1] = create_unhandled_exception_eventargs (exc);
4235 mono_runtime_delegate_invoke (delegate, pa, &e);
4237 if (domain != current_domain)
4238 mono_domain_set_internal_with_options (current_domain, FALSE);
4242 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4243 if (!mono_error_ok (&error)) {
4244 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4245 mono_error_cleanup (&error);
4247 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4253 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4256 * mono_runtime_unhandled_exception_policy_set:
4257 * @policy: the new policy
4259 * This is a VM internal routine.
4261 * Sets the runtime policy for handling unhandled exceptions.
4264 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4265 runtime_unhandled_exception_policy = policy;
4269 * mono_runtime_unhandled_exception_policy_get:
4271 * This is a VM internal routine.
4273 * Gets the runtime policy for handling unhandled exceptions.
4275 MonoRuntimeUnhandledExceptionPolicy
4276 mono_runtime_unhandled_exception_policy_get (void) {
4277 return runtime_unhandled_exception_policy;
4281 * mono_unhandled_exception:
4282 * @exc: exception thrown
4284 * This is a VM internal routine.
4286 * We call this function when we detect an unhandled exception
4287 * in the default domain.
4289 * It invokes the * UnhandledException event in AppDomain or prints
4290 * a warning to the console
4293 mono_unhandled_exception (MonoObject *exc)
4295 MONO_REQ_GC_UNSAFE_MODE;
4297 MonoClassField *field;
4298 MonoDomain *current_domain, *root_domain;
4299 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4301 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4304 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4307 current_domain = mono_domain_get ();
4308 root_domain = mono_get_root_domain ();
4310 root_appdomain_delegate = mono_field_get_value_object (root_domain, field, (MonoObject*) root_domain->domain);
4311 if (current_domain != root_domain)
4312 current_appdomain_delegate = mono_field_get_value_object (current_domain, field, (MonoObject*) current_domain->domain);
4314 /* set exitcode only if we will abort the process */
4315 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4316 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4317 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4319 mono_environment_exitcode_set (1);
4322 mono_print_unhandled_exception (exc);
4324 if (root_appdomain_delegate)
4325 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4326 if (current_appdomain_delegate)
4327 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4332 * mono_runtime_exec_managed_code:
4333 * @domain: Application domain
4334 * @main_func: function to invoke from the execution thread
4335 * @main_args: parameter to the main_func
4337 * Launch a new thread to execute a function
4339 * main_func is called back from the thread with main_args as the
4340 * parameter. The callback function is expected to start Main()
4341 * eventually. This function then waits for all managed threads to
4343 * It is not necesseray anymore to execute managed code in a subthread,
4344 * so this function should not be used anymore by default: just
4345 * execute the code and then call mono_thread_manage ().
4348 mono_runtime_exec_managed_code (MonoDomain *domain,
4349 MonoMainThreadFunc main_func,
4352 mono_thread_create (domain, main_func, main_args);
4354 mono_thread_manage ();
4358 * Execute a standard Main() method (args doesn't contain the
4362 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4364 MONO_REQ_GC_UNSAFE_MODE;
4370 MonoCustomAttrInfo* cinfo;
4371 gboolean has_stathread_attribute;
4372 MonoInternalThread* thread = mono_thread_internal_current ();
4378 domain = mono_object_domain (args);
4379 if (!domain->entry_assembly) {
4381 MonoAssembly *assembly;
4383 assembly = method->klass->image->assembly;
4384 domain->entry_assembly = assembly;
4385 /* Domains created from another domain already have application_base and configuration_file set */
4386 if (domain->setup->application_base == NULL) {
4387 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4390 if (domain->setup->configuration_file == NULL) {
4391 str = g_strconcat (assembly->image->name, ".config", NULL);
4392 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4394 mono_domain_set_options_from_config (domain);
4398 cinfo = mono_custom_attrs_from_method_checked (method, &error);
4399 mono_error_cleanup (&error); /* FIXME warn here? */
4401 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4403 mono_custom_attrs_free (cinfo);
4405 has_stathread_attribute = FALSE;
4407 if (has_stathread_attribute) {
4408 thread->apartment_state = ThreadApartmentState_STA;
4410 thread->apartment_state = ThreadApartmentState_MTA;
4412 mono_thread_init_apartment_state ();
4414 /* FIXME: check signature of method */
4415 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4418 res = mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4419 if (*exc == NULL && !mono_error_ok (&error))
4420 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4422 mono_error_cleanup (&error);
4424 res = mono_runtime_invoke_checked (method, NULL, pa, &error);
4425 mono_error_raise_exception (&error); /* FIXME don't raise here */
4429 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4433 mono_environment_exitcode_set (rval);
4436 mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4437 if (*exc == NULL && !mono_error_ok (&error))
4438 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4440 mono_error_cleanup (&error);
4442 mono_runtime_invoke_checked (method, NULL, pa, &error);
4443 mono_error_raise_exception (&error); /* FIXME don't raise here */
4449 /* If the return type of Main is void, only
4450 * set the exitcode if an exception was thrown
4451 * (we don't want to blow away an
4452 * explicitly-set exit code)
4455 mono_environment_exitcode_set (rval);
4463 * mono_runtime_invoke_array:
4464 * @method: method to invoke
4465 * @obJ: object instance
4466 * @params: arguments to the method
4467 * @exc: exception information.
4469 * Invokes the method represented by @method on the object @obj.
4471 * obj is the 'this' pointer, it should be NULL for static
4472 * methods, a MonoObject* for object instances and a pointer to
4473 * the value type for value types.
4475 * The params array contains the arguments to the method with the
4476 * same convention: MonoObject* pointers for object instances and
4477 * pointers to the value type otherwise. The _invoke_array
4478 * variant takes a C# object[] as the params argument (MonoArray
4479 * *params): in this case the value types are boxed inside the
4480 * respective reference representation.
4482 * From unmanaged code you'll usually use the
4483 * mono_runtime_invoke_checked() variant.
4485 * Note that this function doesn't handle virtual methods for
4486 * you, it will exec the exact method you pass: we still need to
4487 * expose a function to lookup the derived class implementation
4488 * of a virtual method (there are examples of this in the code,
4491 * You can pass NULL as the exc argument if you don't want to
4492 * catch exceptions, otherwise, *exc will be set to the exception
4493 * thrown, if any. if an exception is thrown, you can't use the
4494 * MonoObject* result from the function.
4496 * If the method returns a value type, it is boxed in an object
4500 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4503 MONO_REQ_GC_UNSAFE_MODE;
4506 MonoMethodSignature *sig = mono_method_signature (method);
4507 gpointer *pa = NULL;
4510 gboolean has_byref_nullables = FALSE;
4512 if (NULL != params) {
4513 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4514 for (i = 0; i < mono_array_length (params); i++) {
4515 MonoType *t = sig->params [i];
4521 case MONO_TYPE_BOOLEAN:
4524 case MONO_TYPE_CHAR:
4533 case MONO_TYPE_VALUETYPE:
4534 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4535 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4536 pa [i] = mono_array_get (params, MonoObject*, i);
4538 has_byref_nullables = TRUE;
4540 /* MS seems to create the objects if a null is passed in */
4541 if (!mono_array_get (params, MonoObject*, i)) {
4542 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (sig->params [i]), &error);
4543 mono_error_raise_exception (&error); /* FIXME don't raise here */
4544 mono_array_setref (params, i, o);
4549 * We can't pass the unboxed vtype byref to the callee, since
4550 * that would mean the callee would be able to modify boxed
4551 * primitive types. So we (and MS) make a copy of the boxed
4552 * object, pass that to the callee, and replace the original
4553 * boxed object in the arg array with the copy.
4555 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4556 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4557 mono_array_setref (params, i, copy);
4560 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4563 case MONO_TYPE_STRING:
4564 case MONO_TYPE_OBJECT:
4565 case MONO_TYPE_CLASS:
4566 case MONO_TYPE_ARRAY:
4567 case MONO_TYPE_SZARRAY:
4569 pa [i] = mono_array_addr (params, MonoObject*, i);
4570 // FIXME: I need to check this code path
4572 pa [i] = mono_array_get (params, MonoObject*, i);
4574 case MONO_TYPE_GENERICINST:
4576 t = &t->data.generic_class->container_class->this_arg;
4578 t = &t->data.generic_class->container_class->byval_arg;
4580 case MONO_TYPE_PTR: {
4583 /* The argument should be an IntPtr */
4584 arg = mono_array_get (params, MonoObject*, i);
4588 g_assert (arg->vtable->klass == mono_defaults.int_class);
4589 pa [i] = ((MonoIntPtr*)arg)->m_value;
4594 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4599 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4602 if (mono_class_is_nullable (method->klass)) {
4603 /* Need to create a boxed vtype instead */
4609 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4613 obj = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4614 g_assert (obj && mono_error_ok (&error)); /*maybe we should raise a TLE instead?*/ /* FIXME don't swallow error */
4615 #ifndef DISABLE_REMOTING
4616 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4617 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4620 if (method->klass->valuetype)
4621 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
4624 } else if (method->klass->valuetype) {
4625 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4629 mono_runtime_try_invoke (method, o, pa, exc, &error);
4630 if (*exc == NULL && !mono_error_ok (&error))
4631 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4633 mono_error_cleanup (&error);
4635 mono_runtime_invoke_checked (method, o, pa, &error);
4636 mono_error_raise_exception (&error); /* FIXME don't raise here */
4639 return (MonoObject *)obj;
4641 if (mono_class_is_nullable (method->klass)) {
4642 MonoObject *nullable;
4644 /* Convert the unboxed vtype into a Nullable structure */
4645 nullable = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4646 mono_error_raise_exception (&error); /* FIXME don't raise here */
4648 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4649 obj = mono_object_unbox (nullable);
4652 /* obj must be already unboxed if needed */
4654 res = mono_runtime_try_invoke (method, obj, pa, exc, &error);
4655 if (*exc == NULL && !mono_error_ok (&error))
4656 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4658 mono_error_cleanup (&error);
4660 res = mono_runtime_invoke_checked (method, obj, pa, &error);
4661 mono_error_raise_exception (&error); /* FIXME don't raise here */
4664 if (sig->ret->type == MONO_TYPE_PTR) {
4665 MonoClass *pointer_class;
4666 static MonoMethod *box_method;
4668 MonoObject *box_exc;
4671 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4672 * convert it to a Pointer object.
4674 pointer_class = mono_class_get_pointer_class ();
4676 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4678 g_assert (res->vtable->klass == mono_defaults.int_class);
4679 box_args [0] = ((MonoIntPtr*)res)->m_value;
4680 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, &error);
4681 mono_error_raise_exception (&error); /* FIXME don't raise here */
4683 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, &error);
4684 g_assert (box_exc == NULL);
4685 mono_error_assert_ok (&error);
4688 if (has_byref_nullables) {
4690 * The runtime invoke wrapper already converted byref nullables back,
4691 * and stored them in pa, we just need to copy them back to the
4694 for (i = 0; i < mono_array_length (params); i++) {
4695 MonoType *t = sig->params [i];
4697 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4698 mono_array_setref (params, i, pa [i]);
4708 * @klass: the class of the object that we want to create
4710 * Returns: a newly created object whose definition is
4711 * looked up using @klass. This will not invoke any constructors,
4712 * so the consumer of this routine has to invoke any constructors on
4713 * its own to initialize the object.
4715 * It returns NULL on failure.
4718 mono_object_new (MonoDomain *domain, MonoClass *klass)
4720 MONO_REQ_GC_UNSAFE_MODE;
4724 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4726 mono_error_raise_exception (&error);
4731 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
4733 MONO_REQ_GC_UNSAFE_MODE;
4737 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4739 mono_error_raise_exception (&error);
4744 * mono_object_new_checked:
4745 * @klass: the class of the object that we want to create
4746 * @error: set on error
4748 * Returns: a newly created object whose definition is
4749 * looked up using @klass. This will not invoke any constructors,
4750 * so the consumer of this routine has to invoke any constructors on
4751 * its own to initialize the object.
4753 * It returns NULL on failure and sets @error.
4756 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
4758 MONO_REQ_GC_UNSAFE_MODE;
4762 vtable = mono_class_vtable (domain, klass);
4763 g_assert (vtable); /* FIXME don't swallow the error */
4765 MonoObject *o = mono_object_new_specific_checked (vtable, error);
4770 * mono_object_new_pinned:
4772 * Same as mono_object_new, but the returned object will be pinned.
4773 * For SGEN, these objects will only be freed at appdomain unload.
4776 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
4778 MONO_REQ_GC_UNSAFE_MODE;
4782 mono_error_init (error);
4784 vtable = mono_class_vtable (domain, klass);
4785 g_assert (vtable); /* FIXME don't swallow the error */
4787 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4789 if (G_UNLIKELY (!o))
4790 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
4791 else if (G_UNLIKELY (vtable->klass->has_finalize))
4792 mono_object_register_finalizer (o, error);
4798 * mono_object_new_specific:
4799 * @vtable: the vtable of the object that we want to create
4801 * Returns: A newly created object with class and domain specified
4805 mono_object_new_specific (MonoVTable *vtable)
4808 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4809 mono_error_raise_exception (&error);
4815 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
4817 MONO_REQ_GC_UNSAFE_MODE;
4821 mono_error_init (error);
4823 /* check for is_com_object for COM Interop */
4824 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4827 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4830 MonoClass *klass = mono_class_get_activation_services_class ();
4833 mono_class_init (klass);
4835 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4837 mono_error_set_generic_error (error, "System", "NotSupportedException", "Linked away.");
4840 vtable->domain->create_proxy_for_type_method = im;
4843 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
4844 if (!mono_error_ok (error))
4847 o = mono_runtime_invoke_checked (im, NULL, pa, error);
4848 if (!mono_error_ok (error))
4855 return mono_object_new_alloc_specific_checked (vtable, error);
4859 ves_icall_object_new_specific (MonoVTable *vtable)
4862 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4863 mono_error_raise_exception (&error);
4869 * mono_object_new_alloc_specific:
4870 * @vtable: virtual table for the object.
4872 * This function allocates a new `MonoObject` with the type derived
4873 * from the @vtable information. If the class of this object has a
4874 * finalizer, then the object will be tracked for finalization.
4876 * This method might raise an exception on errors. Use the
4877 * `mono_object_new_fast_checked` method if you want to manually raise
4880 * Returns: the allocated object.
4883 mono_object_new_alloc_specific (MonoVTable *vtable)
4886 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
4887 mono_error_raise_exception (&error);
4893 * mono_object_new_alloc_specific_checked:
4894 * @vtable: virtual table for the object.
4895 * @error: holds the error return value.
4897 * This function allocates a new `MonoObject` with the type derived
4898 * from the @vtable information. If the class of this object has a
4899 * finalizer, then the object will be tracked for finalization.
4901 * If there is not enough memory, the @error parameter will be set
4902 * and will contain a user-visible message with the amount of bytes
4903 * that were requested.
4905 * Returns: the allocated object, or NULL if there is not enough memory
4909 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
4911 MONO_REQ_GC_UNSAFE_MODE;
4915 mono_error_init (error);
4917 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4919 if (G_UNLIKELY (!o))
4920 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4921 else if (G_UNLIKELY (vtable->klass->has_finalize))
4922 mono_object_register_finalizer (o, error);
4928 * mono_object_new_fast:
4929 * @vtable: virtual table for the object.
4931 * This function allocates a new `MonoObject` with the type derived
4932 * from the @vtable information. The returned object is not tracked
4933 * for finalization. If your object implements a finalizer, you should
4934 * use `mono_object_new_alloc_specific` instead.
4936 * This method might raise an exception on errors. Use the
4937 * `mono_object_new_fast_checked` method if you want to manually raise
4940 * Returns: the allocated object.
4943 mono_object_new_fast (MonoVTable *vtable)
4946 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4947 mono_error_raise_exception (&error);
4953 * mono_object_new_fast_checked:
4954 * @vtable: virtual table for the object.
4955 * @error: holds the error return value.
4957 * This function allocates a new `MonoObject` with the type derived
4958 * from the @vtable information. The returned object is not tracked
4959 * for finalization. If your object implements a finalizer, you should
4960 * use `mono_object_new_alloc_specific_checked` instead.
4962 * If there is not enough memory, the @error parameter will be set
4963 * and will contain a user-visible message with the amount of bytes
4964 * that were requested.
4966 * Returns: the allocated object, or NULL if there is not enough memory
4970 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
4972 MONO_REQ_GC_UNSAFE_MODE;
4976 mono_error_init (error);
4978 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4980 if (G_UNLIKELY (!o))
4981 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4987 ves_icall_object_new_fast (MonoVTable *vtable)
4990 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4991 mono_error_raise_exception (&error);
4997 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
4999 MONO_REQ_GC_UNSAFE_MODE;
5003 mono_error_init (error);
5005 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5007 if (G_UNLIKELY (!o))
5008 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5009 else if (G_UNLIKELY (vtable->klass->has_finalize))
5010 mono_object_register_finalizer (o, error);
5016 * mono_class_get_allocation_ftn:
5018 * @for_box: the object will be used for boxing
5019 * @pass_size_in_words:
5021 * Return the allocation function appropriate for the given class.
5025 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5027 MONO_REQ_GC_NEUTRAL_MODE;
5029 *pass_size_in_words = FALSE;
5031 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
5032 return ves_icall_object_new_specific;
5034 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5036 return ves_icall_object_new_fast;
5039 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5040 * of the overhead of parameter passing.
5043 *pass_size_in_words = TRUE;
5044 #ifdef GC_REDIRECT_TO_LOCAL
5045 return GC_local_gcj_fast_malloc;
5047 return GC_gcj_fast_malloc;
5052 return ves_icall_object_new_specific;
5056 * mono_object_new_from_token:
5057 * @image: Context where the type_token is hosted
5058 * @token: a token of the type that we want to create
5060 * Returns: A newly created object whose definition is
5061 * looked up using @token in the @image image
5064 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5066 MONO_REQ_GC_UNSAFE_MODE;
5072 klass = mono_class_get_checked (image, token, &error);
5073 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
5075 result = mono_object_new_checked (domain, klass, &error);
5077 mono_error_raise_exception (&error); /* FIXME don't raise here */
5084 * mono_object_clone:
5085 * @obj: the object to clone
5087 * Returns: A newly created object who is a shallow copy of @obj
5090 mono_object_clone (MonoObject *obj)
5093 MonoObject *o = mono_object_clone_checked (obj, &error);
5094 mono_error_raise_exception (&error);
5100 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5102 MONO_REQ_GC_UNSAFE_MODE;
5107 mono_error_init (error);
5109 size = obj->vtable->klass->instance_size;
5111 if (obj->vtable->klass->rank)
5112 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
5114 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5116 if (G_UNLIKELY (!o)) {
5117 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5121 /* If the object doesn't contain references this will do a simple memmove. */
5122 mono_gc_wbarrier_object_copy (o, obj);
5124 if (obj->vtable->klass->has_finalize)
5125 mono_object_register_finalizer (o, error);
5130 * mono_array_full_copy:
5131 * @src: source array to copy
5132 * @dest: destination array
5134 * Copies the content of one array to another with exactly the same type and size.
5137 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5139 MONO_REQ_GC_UNSAFE_MODE;
5142 MonoClass *klass = src->obj.vtable->klass;
5144 g_assert (klass == dest->obj.vtable->klass);
5146 size = mono_array_length (src);
5147 g_assert (size == mono_array_length (dest));
5148 size *= mono_array_element_size (klass);
5150 if (klass->element_class->valuetype) {
5151 if (klass->element_class->has_references)
5152 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5154 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5156 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5159 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5164 * mono_array_clone_in_domain:
5165 * @domain: the domain in which the array will be cloned into
5166 * @array: the array to clone
5168 * This routine returns a copy of the array that is hosted on the
5169 * specified MonoDomain.
5172 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
5174 MONO_REQ_GC_UNSAFE_MODE;
5180 MonoClass *klass = array->obj.vtable->klass;
5182 if (array->bounds == NULL) {
5183 size = mono_array_length (array);
5184 o = mono_array_new_full_checked (domain, klass, &size, NULL, &error);
5185 mono_error_raise_exception (&error); /* FIXME don't raise here */
5187 size *= mono_array_element_size (klass);
5189 if (klass->element_class->valuetype) {
5190 if (klass->element_class->has_references)
5191 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5193 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5195 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5198 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5203 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5204 size = mono_array_element_size (klass);
5205 for (i = 0; i < klass->rank; ++i) {
5206 sizes [i] = array->bounds [i].length;
5207 size *= array->bounds [i].length;
5208 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5210 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, &error);
5211 mono_error_raise_exception (&error); /* FIXME don't raise here */
5213 if (klass->element_class->valuetype) {
5214 if (klass->element_class->has_references)
5215 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5217 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5219 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5222 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5230 * @array: the array to clone
5232 * Returns: A newly created array who is a shallow copy of @array
5235 mono_array_clone (MonoArray *array)
5237 MONO_REQ_GC_UNSAFE_MODE;
5239 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
5242 /* helper macros to check for overflow when calculating the size of arrays */
5243 #ifdef MONO_BIG_ARRAYS
5244 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5245 #define MYGUINT_MAX MYGUINT64_MAX
5246 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5247 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5248 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5249 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5250 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5252 #define MYGUINT32_MAX 4294967295U
5253 #define MYGUINT_MAX MYGUINT32_MAX
5254 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5255 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5256 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5257 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5258 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5262 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5264 MONO_REQ_GC_NEUTRAL_MODE;
5268 byte_len = mono_array_element_size (klass);
5269 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5272 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5274 byte_len += MONO_SIZEOF_MONO_ARRAY;
5282 * mono_array_new_full:
5283 * @domain: domain where the object is created
5284 * @array_class: array class
5285 * @lengths: lengths for each dimension in the array
5286 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5288 * This routine creates a new array objects with the given dimensions,
5289 * lower bounds and type.
5292 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5295 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5296 mono_error_raise_exception (&error);
5302 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5304 MONO_REQ_GC_UNSAFE_MODE;
5306 uintptr_t byte_len = 0, len, bounds_size;
5309 MonoArrayBounds *bounds;
5313 mono_error_init (error);
5315 if (!array_class->inited)
5316 mono_class_init (array_class);
5320 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5321 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5323 if (len > MONO_ARRAY_MAX_INDEX) {
5324 mono_error_set_generic_error (error, "System", "OverflowException", "");
5329 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5331 for (i = 0; i < array_class->rank; ++i) {
5332 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5333 mono_error_set_generic_error (error, "System", "OverflowException", "");
5336 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5337 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5344 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5345 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5351 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5352 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5355 byte_len = (byte_len + 3) & ~3;
5356 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5357 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5360 byte_len += bounds_size;
5363 * Following three lines almost taken from mono_object_new ():
5364 * they need to be kept in sync.
5366 vtable = mono_class_vtable_full (domain, array_class, error);
5367 return_val_if_nok (error, NULL);
5370 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5372 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5374 if (G_UNLIKELY (!o)) {
5375 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5379 array = (MonoArray*)o;
5381 bounds = array->bounds;
5384 for (i = 0; i < array_class->rank; ++i) {
5385 bounds [i].length = lengths [i];
5387 bounds [i].lower_bound = lower_bounds [i];
5396 * @domain: domain where the object is created
5397 * @eclass: element class
5398 * @n: number of array elements
5400 * This routine creates a new szarray with @n elements of type @eclass.
5403 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5405 MONO_REQ_GC_UNSAFE_MODE;
5411 ac = mono_array_class_get (eclass, 1);
5414 MonoVTable *vtable = mono_class_vtable_full (domain, ac, &error);
5415 mono_error_raise_exception (&error); /* FIXME don't raise here */
5417 arr = mono_array_new_specific_checked (vtable, n, &error);
5418 mono_error_raise_exception (&error); /* FIXME don't raise here */
5424 * mono_array_new_specific:
5425 * @vtable: a vtable in the appropriate domain for an initialized class
5426 * @n: number of array elements
5428 * This routine is a fast alternative to mono_array_new() for code which
5429 * can be sure about the domain it operates in.
5432 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5435 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5436 mono_error_raise_exception (&error); /* FIXME don't raise here */
5442 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5444 MONO_REQ_GC_UNSAFE_MODE;
5449 mono_error_init (error);
5451 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5452 mono_error_set_generic_error (error, "System", "OverflowException", "");
5456 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5457 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5460 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5462 if (G_UNLIKELY (!o)) {
5463 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5467 return (MonoArray*)o;
5471 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5474 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5475 mono_error_raise_exception (&error);
5481 * mono_string_new_utf16:
5482 * @text: a pointer to an utf16 string
5483 * @len: the length of the string
5485 * Returns: A newly created string object which contains @text.
5488 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5490 MONO_REQ_GC_UNSAFE_MODE;
5493 MonoString *res = NULL;
5494 res = mono_string_new_utf16_checked (domain, text, len, &error);
5495 mono_error_raise_exception (&error);
5501 * mono_string_new_utf16_checked:
5502 * @text: a pointer to an utf16 string
5503 * @len: the length of the string
5504 * @error: written on error.
5506 * Returns: A newly created string object which contains @text.
5507 * On error, returns NULL and sets @error.
5510 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5512 MONO_REQ_GC_UNSAFE_MODE;
5516 mono_error_init (error);
5518 s = mono_string_new_size_checked (domain, len, error);
5520 memcpy (mono_string_chars (s), text, len * 2);
5526 * mono_string_new_utf32:
5527 * @text: a pointer to an utf32 string
5528 * @len: the length of the string
5530 * Returns: A newly created string object which contains @text.
5533 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5535 MONO_REQ_GC_UNSAFE_MODE;
5539 mono_unichar2 *utf16_output = NULL;
5540 gint32 utf16_len = 0;
5541 GError *gerror = NULL;
5542 glong items_written;
5544 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
5547 g_error_free (gerror);
5549 while (utf16_output [utf16_len]) utf16_len++;
5551 s = mono_string_new_size_checked (domain, utf16_len, &error);
5552 mono_error_raise_exception (&error); /* FIXME don't raise here */
5554 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5556 g_free (utf16_output);
5562 * mono_string_new_size:
5563 * @text: a pointer to an utf16 string
5564 * @len: the length of the string
5566 * Returns: A newly created string object of @len
5569 mono_string_new_size (MonoDomain *domain, gint32 len)
5572 MonoString *str = mono_string_new_size_checked (domain, len, &error);
5573 mono_error_raise_exception (&error);
5579 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
5581 MONO_REQ_GC_UNSAFE_MODE;
5587 mono_error_init (error);
5589 /* check for overflow */
5590 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
5591 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
5595 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5596 g_assert (size > 0);
5598 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5601 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
5603 if (G_UNLIKELY (!s)) {
5604 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5612 * mono_string_new_len:
5613 * @text: a pointer to an utf8 string
5614 * @length: number of bytes in @text to consider
5616 * Returns: A newly created string object which contains @text.
5619 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5621 MONO_REQ_GC_UNSAFE_MODE;
5624 GError *eg_error = NULL;
5625 MonoString *o = NULL;
5627 glong items_written;
5629 mono_error_init (&error);
5631 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
5634 o = mono_string_new_utf16_checked (domain, ut, items_written, &error);
5636 g_error_free (eg_error);
5640 mono_error_raise_exception (&error); /* FIXME don't raise here */
5646 * @text: a pointer to an utf8 string
5648 * Returns: A newly created string object which contains @text.
5650 * This function asserts if it cannot allocate a new string.
5652 * @deprecated Use mono_string_new_checked in new code.
5655 mono_string_new (MonoDomain *domain, const char *text)
5658 MonoString *res = NULL;
5659 res = mono_string_new_checked (domain, text, &error);
5660 mono_error_assert_ok (&error);
5665 * mono_string_new_checked:
5666 * @text: a pointer to an utf8 string
5667 * @merror: set on error
5669 * Returns: A newly created string object which contains @text.
5670 * On error returns NULL and sets @merror.
5673 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
5675 MONO_REQ_GC_UNSAFE_MODE;
5677 GError *eg_error = NULL;
5678 MonoString *o = NULL;
5680 glong items_written;
5683 mono_error_init (error);
5687 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
5690 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
5692 g_error_free (eg_error);
5695 mono_error_raise_exception (error);
5697 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5702 MonoString *o = NULL;
5704 if (!g_utf8_validate (text, -1, &end)) {
5705 mono_error_set_argument (error, "text", "Not a valid utf8 string");
5709 len = g_utf8_strlen (text, -1);
5710 o = mono_string_new_size_checked (domain, len, error);
5713 str = mono_string_chars (o);
5715 while (text < end) {
5716 *str++ = g_utf8_get_char (text);
5717 text = g_utf8_next_char (text);
5726 * mono_string_new_wrapper:
5727 * @text: pointer to utf8 characters.
5729 * Helper function to create a string object from @text in the current domain.
5732 mono_string_new_wrapper (const char *text)
5734 MONO_REQ_GC_UNSAFE_MODE;
5736 MonoDomain *domain = mono_domain_get ();
5739 return mono_string_new (domain, text);
5746 * @class: the class of the value
5747 * @value: a pointer to the unboxed data
5749 * Returns: A newly created object which contains @value.
5752 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
5754 MONO_REQ_GC_UNSAFE_MODE;
5761 g_assert (klass->valuetype);
5762 if (mono_class_is_nullable (klass))
5763 return mono_nullable_box ((guint8 *)value, klass);
5765 vtable = mono_class_vtable (domain, klass);
5768 size = mono_class_instance_size (klass);
5769 res = mono_object_new_alloc_specific_checked (vtable, &error);
5770 mono_error_raise_exception (&error); /* FIXME don't raise here */
5772 size = size - sizeof (MonoObject);
5775 g_assert (size == mono_class_value_size (klass, NULL));
5776 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
5778 #if NO_UNALIGNED_ACCESS
5779 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5783 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5786 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5789 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5792 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5795 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5799 if (klass->has_finalize) {
5800 mono_object_register_finalizer (res, &error);
5801 mono_error_raise_exception (&error); /* FIXME don't raise here */
5808 * @dest: destination pointer
5809 * @src: source pointer
5810 * @klass: a valuetype class
5812 * Copy a valuetype from @src to @dest. This function must be used
5813 * when @klass contains references fields.
5816 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5818 MONO_REQ_GC_UNSAFE_MODE;
5820 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5824 * mono_value_copy_array:
5825 * @dest: destination array
5826 * @dest_idx: index in the @dest array
5827 * @src: source pointer
5828 * @count: number of items
5830 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5831 * This function must be used when @klass contains references fields.
5832 * Overlap is handled.
5835 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5837 MONO_REQ_GC_UNSAFE_MODE;
5839 int size = mono_array_element_size (dest->obj.vtable->klass);
5840 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5841 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5842 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5846 * mono_object_get_domain:
5847 * @obj: object to query
5849 * Returns: the MonoDomain where the object is hosted
5852 mono_object_get_domain (MonoObject *obj)
5854 MONO_REQ_GC_UNSAFE_MODE;
5856 return mono_object_domain (obj);
5860 * mono_object_get_class:
5861 * @obj: object to query
5863 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
5865 * Returns: the MonoClass of the object.
5868 mono_object_get_class (MonoObject *obj)
5870 MONO_REQ_GC_UNSAFE_MODE;
5872 return mono_object_class (obj);
5875 * mono_object_get_size:
5876 * @o: object to query
5878 * Returns: the size, in bytes, of @o
5881 mono_object_get_size (MonoObject* o)
5883 MONO_REQ_GC_UNSAFE_MODE;
5885 MonoClass* klass = mono_object_class (o);
5886 if (klass == mono_defaults.string_class) {
5887 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5888 } else if (o->vtable->rank) {
5889 MonoArray *array = (MonoArray*)o;
5890 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
5891 if (array->bounds) {
5894 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5898 return mono_class_instance_size (klass);
5903 * mono_object_unbox:
5904 * @obj: object to unbox
5906 * Returns: a pointer to the start of the valuetype boxed in this
5909 * This method will assert if the object passed is not a valuetype.
5912 mono_object_unbox (MonoObject *obj)
5914 MONO_REQ_GC_UNSAFE_MODE;
5916 /* add assert for valuetypes? */
5917 g_assert (obj->vtable->klass->valuetype);
5918 return ((char*)obj) + sizeof (MonoObject);
5922 * mono_object_isinst:
5924 * @klass: a pointer to a class
5926 * Returns: @obj if @obj is derived from @klass
5929 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5931 MONO_REQ_GC_UNSAFE_MODE;
5934 mono_class_init (klass);
5936 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5937 return mono_object_isinst_mbyref (obj, klass);
5942 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5946 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5948 MONO_REQ_GC_UNSAFE_MODE;
5958 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5959 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5963 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5964 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5967 MonoClass *oklass = vt->klass;
5968 if (mono_class_is_transparent_proxy (oklass))
5969 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5971 mono_class_setup_supertypes (klass);
5972 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5975 #ifndef DISABLE_REMOTING
5976 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5978 MonoDomain *domain = mono_domain_get ();
5980 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5981 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5982 MonoMethod *im = NULL;
5985 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5987 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
5988 im = mono_object_get_virtual_method (rp, im);
5991 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
5992 mono_error_raise_exception (&error); /* FIXME don't raise here */
5995 res = mono_runtime_invoke_checked (im, rp, pa, &error);
5996 mono_error_raise_exception (&error); /* FIXME don't raise here */
5998 if (*(MonoBoolean *) mono_object_unbox(res)) {
5999 /* Update the vtable of the remote type, so it can safely cast to this new type */
6000 mono_upgrade_remote_class (domain, obj, klass);
6004 #endif /* DISABLE_REMOTING */
6009 * mono_object_castclass_mbyref:
6011 * @klass: a pointer to a class
6013 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
6016 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
6018 MONO_REQ_GC_UNSAFE_MODE;
6020 if (!obj) return NULL;
6021 if (mono_object_isinst_mbyref (obj, klass)) return obj;
6023 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
6025 "InvalidCastException"));
6030 MonoDomain *orig_domain;
6036 str_lookup (MonoDomain *domain, gpointer user_data)
6038 MONO_REQ_GC_UNSAFE_MODE;
6040 LDStrInfo *info = (LDStrInfo *)user_data;
6041 if (info->res || domain == info->orig_domain)
6043 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6047 mono_string_get_pinned (MonoString *str, MonoError *error)
6049 MONO_REQ_GC_UNSAFE_MODE;
6051 mono_error_init (error);
6053 /* We only need to make a pinned version of a string if this is a moving GC */
6054 if (!mono_gc_is_moving ())
6058 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6059 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6061 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6062 news->length = mono_string_length (str);
6064 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6070 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6072 MONO_REQ_GC_UNSAFE_MODE;
6074 MonoGHashTable *ldstr_table;
6075 MonoString *s, *res;
6078 mono_error_init (error);
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 return_val_if_nok (error, NULL);
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)
6135 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6136 /* This function does not fail. */
6137 mono_error_assert_ok (&error);
6142 * mono_string_intern:
6143 * @o: String to intern
6145 * Interns the string passed.
6146 * Returns: The interned string.
6149 mono_string_intern (MonoString *str)
6152 MonoString *result = mono_string_intern_checked (str, &error);
6153 mono_error_assert_ok (&error);
6158 * mono_string_intern_checked:
6159 * @o: String to intern
6160 * @error: set on error.
6162 * Interns the string passed.
6163 * Returns: The interned string. On failure returns NULL and sets @error
6166 mono_string_intern_checked (MonoString *str, MonoError *error)
6168 MONO_REQ_GC_UNSAFE_MODE;
6170 mono_error_init (error);
6172 return mono_string_is_interned_lookup (str, TRUE, error);
6177 * @domain: the domain where the string will be used.
6178 * @image: a metadata context
6179 * @idx: index into the user string table.
6181 * Implementation for the ldstr opcode.
6182 * Returns: a loaded string from the @image/@idx combination.
6185 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6187 MONO_REQ_GC_UNSAFE_MODE;
6189 if (image->dynamic) {
6190 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
6193 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6194 return NULL; /*FIXME we should probably be raising an exception here*/
6195 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
6200 * mono_ldstr_metadata_sig
6201 * @domain: the domain for the string
6202 * @sig: the signature of a metadata string
6204 * Returns: a MonoString for a string stored in the metadata
6207 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
6209 MONO_REQ_GC_UNSAFE_MODE;
6212 const char *str = sig;
6213 MonoString *o, *interned;
6216 len2 = mono_metadata_decode_blob_size (str, &str);
6219 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, &error);
6220 mono_error_raise_exception (&error); /* FIXME don't raise here */
6221 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6224 guint16 *p2 = (guint16*)mono_string_chars (o);
6225 for (i = 0; i < len2; ++i) {
6226 *p2 = GUINT16_FROM_LE (*p2);
6232 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6235 return interned; /* o will get garbage collected */
6237 o = mono_string_get_pinned (o, &error);
6238 mono_error_raise_exception (&error); /* FIXME don't raise here */
6241 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6243 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6253 * mono_string_to_utf8:
6254 * @s: a System.String
6256 * Returns the UTF8 representation for @s.
6257 * The resulting buffer needs to be freed with mono_free().
6259 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6262 mono_string_to_utf8 (MonoString *s)
6264 MONO_REQ_GC_UNSAFE_MODE;
6267 char *result = mono_string_to_utf8_checked (s, &error);
6269 if (!mono_error_ok (&error))
6270 mono_error_raise_exception (&error);
6275 * mono_string_to_utf8_checked:
6276 * @s: a System.String
6277 * @error: a MonoError.
6279 * Converts a MonoString to its UTF8 representation. May fail; check
6280 * @error to determine whether the conversion was successful.
6281 * The resulting buffer should be freed with mono_free().
6284 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6286 MONO_REQ_GC_UNSAFE_MODE;
6290 GError *gerror = NULL;
6292 mono_error_init (error);
6298 return g_strdup ("");
6300 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6302 mono_error_set_argument (error, "string", "%s", gerror->message);
6303 g_error_free (gerror);
6306 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6307 if (s->length > written) {
6308 /* allocate the total length and copy the part of the string that has been converted */
6309 char *as2 = (char *)g_malloc0 (s->length);
6310 memcpy (as2, as, written);
6319 * mono_string_to_utf8_ignore:
6322 * Converts a MonoString to its UTF8 representation. Will ignore
6323 * invalid surrogate pairs.
6324 * The resulting buffer should be freed with mono_free().
6328 mono_string_to_utf8_ignore (MonoString *s)
6330 MONO_REQ_GC_UNSAFE_MODE;
6339 return g_strdup ("");
6341 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6343 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6344 if (s->length > written) {
6345 /* allocate the total length and copy the part of the string that has been converted */
6346 char *as2 = (char *)g_malloc0 (s->length);
6347 memcpy (as2, as, written);
6356 * mono_string_to_utf8_image_ignore:
6357 * @s: a System.String
6359 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6362 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
6364 MONO_REQ_GC_UNSAFE_MODE;
6366 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
6370 * mono_string_to_utf8_mp_ignore:
6371 * @s: a System.String
6373 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
6376 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
6378 MONO_REQ_GC_UNSAFE_MODE;
6380 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
6385 * mono_string_to_utf16:
6388 * Return an null-terminated array of the utf-16 chars
6389 * contained in @s. The result must be freed with g_free().
6390 * This is a temporary helper until our string implementation
6391 * is reworked to always include the null terminating char.
6394 mono_string_to_utf16 (MonoString *s)
6396 MONO_REQ_GC_UNSAFE_MODE;
6403 as = (char *)g_malloc ((s->length * 2) + 2);
6404 as [(s->length * 2)] = '\0';
6405 as [(s->length * 2) + 1] = '\0';
6408 return (gunichar2 *)(as);
6411 memcpy (as, mono_string_chars(s), s->length * 2);
6412 return (gunichar2 *)(as);
6416 * mono_string_to_utf32:
6419 * Return an null-terminated array of the UTF-32 (UCS-4) chars
6420 * contained in @s. The result must be freed with g_free().
6423 mono_string_to_utf32 (MonoString *s)
6425 MONO_REQ_GC_UNSAFE_MODE;
6427 mono_unichar4 *utf32_output = NULL;
6428 GError *error = NULL;
6429 glong items_written;
6434 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
6437 g_error_free (error);
6439 return utf32_output;
6443 * mono_string_from_utf16:
6444 * @data: the UTF16 string (LPWSTR) to convert
6446 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
6448 * Returns: a MonoString.
6451 mono_string_from_utf16 (gunichar2 *data)
6453 MONO_REQ_GC_UNSAFE_MODE;
6456 MonoString *res = NULL;
6457 MonoDomain *domain = mono_domain_get ();
6463 while (data [len]) len++;
6465 res = mono_string_new_utf16_checked (domain, data, len, &error);
6466 mono_error_raise_exception (&error); /* FIXME don't raise here */
6471 * mono_string_from_utf32:
6472 * @data: the UTF32 string (LPWSTR) to convert
6474 * Converts a UTF32 (UCS-4)to a MonoString.
6476 * Returns: a MonoString.
6479 mono_string_from_utf32 (mono_unichar4 *data)
6481 MONO_REQ_GC_UNSAFE_MODE;
6483 MonoString* result = NULL;
6484 mono_unichar2 *utf16_output = NULL;
6485 GError *error = NULL;
6486 glong items_written;
6492 while (data [len]) len++;
6494 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
6497 g_error_free (error);
6499 result = mono_string_from_utf16 (utf16_output);
6500 g_free (utf16_output);
6505 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
6507 MONO_REQ_GC_UNSAFE_MODE;
6514 r = mono_string_to_utf8_ignore (s);
6516 r = mono_string_to_utf8_checked (s, error);
6517 if (!mono_error_ok (error))
6524 len = strlen (r) + 1;
6526 mp_s = (char *)mono_mempool_alloc (mp, len);
6528 mp_s = (char *)mono_image_alloc (image, len);
6530 memcpy (mp_s, r, len);
6538 * mono_string_to_utf8_image:
6539 * @s: a System.String
6541 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
6544 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
6546 MONO_REQ_GC_UNSAFE_MODE;
6548 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
6552 * mono_string_to_utf8_mp:
6553 * @s: a System.String
6555 * Same as mono_string_to_utf8, but allocate the string from a mempool.
6558 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
6560 MONO_REQ_GC_UNSAFE_MODE;
6562 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
6566 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
6569 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
6571 eh_callbacks = *cbs;
6574 MonoRuntimeExceptionHandlingCallbacks *
6575 mono_get_eh_callbacks (void)
6577 return &eh_callbacks;
6581 * mono_raise_exception:
6582 * @ex: exception object
6584 * Signal the runtime that the exception @ex has been raised in unmanaged code.
6587 mono_raise_exception (MonoException *ex)
6589 MONO_REQ_GC_UNSAFE_MODE;
6592 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
6593 * that will cause gcc to omit the function epilog, causing problems when
6594 * the JIT tries to walk the stack, since the return address on the stack
6595 * will point into the next function in the executable, not this one.
6597 eh_callbacks.mono_raise_exception (ex);
6601 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
6603 MONO_REQ_GC_UNSAFE_MODE;
6605 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
6609 * mono_wait_handle_new:
6610 * @domain: Domain where the object will be created
6611 * @handle: Handle for the wait handle
6613 * Returns: A new MonoWaitHandle created in the given domain for the given handle
6616 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
6618 MONO_REQ_GC_UNSAFE_MODE;
6621 MonoWaitHandle *res;
6622 gpointer params [1];
6623 static MonoMethod *handle_set;
6625 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, &error);
6626 mono_error_raise_exception (&error); /* FIXME don't raise here */
6628 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
6630 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
6632 params [0] = &handle;
6634 mono_runtime_invoke_checked (handle_set, res, params, &error);
6635 mono_error_raise_exception (&error); /* FIXME don't raise here */
6641 mono_wait_handle_get_handle (MonoWaitHandle *handle)
6643 MONO_REQ_GC_UNSAFE_MODE;
6645 static MonoClassField *f_safe_handle = NULL;
6648 if (!f_safe_handle) {
6649 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
6650 g_assert (f_safe_handle);
6653 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
6659 mono_runtime_capture_context (MonoDomain *domain)
6661 MONO_REQ_GC_UNSAFE_MODE;
6663 RuntimeInvokeFunction runtime_invoke;
6665 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
6666 MonoMethod *method = mono_get_context_capture_method ();
6667 MonoMethod *wrapper;
6670 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
6671 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
6672 domain->capture_context_method = mono_compile_method (method);
6675 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
6677 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
6680 * mono_async_result_new:
6681 * @domain:domain where the object will be created.
6682 * @handle: wait handle.
6683 * @state: state to pass to AsyncResult
6684 * @data: C closure data.
6686 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6687 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6691 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6693 MONO_REQ_GC_UNSAFE_MODE;
6696 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, &error);
6697 mono_error_raise_exception (&error); /* FIXME don't raise here */
6698 MonoObject *context = mono_runtime_capture_context (domain);
6699 /* we must capture the execution context from the original thread */
6701 MONO_OBJECT_SETREF (res, execution_context, context);
6702 /* note: result may be null if the flow is suppressed */
6705 res->data = (void **)data;
6706 MONO_OBJECT_SETREF (res, object_data, object_data);
6707 MONO_OBJECT_SETREF (res, async_state, state);
6709 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6711 res->sync_completed = FALSE;
6712 res->completed = FALSE;
6718 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
6720 MONO_REQ_GC_UNSAFE_MODE;
6727 g_assert (ares->async_delegate);
6729 ac = (MonoAsyncCall*) ares->object_data;
6731 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
6733 gpointer wait_event = NULL;
6735 ac->msg->exc = NULL;
6736 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
6737 MONO_OBJECT_SETREF (ac, res, res);
6739 mono_monitor_enter ((MonoObject*) ares);
6740 ares->completed = 1;
6742 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6743 mono_monitor_exit ((MonoObject*) ares);
6745 if (wait_event != NULL)
6746 SetEvent (wait_event);
6748 if (ac->cb_method) {
6749 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
6750 mono_error_raise_exception (&error);
6758 mono_message_init (MonoDomain *domain,
6759 MonoMethodMessage *this_obj,
6760 MonoReflectionMethod *method,
6761 MonoArray *out_args)
6763 MONO_REQ_GC_UNSAFE_MODE;
6765 static MonoClass *object_array_klass;
6766 static MonoClass *byte_array_klass;
6767 static MonoClass *string_array_klass;
6769 MonoMethodSignature *sig = mono_method_signature (method->method);
6776 if (!object_array_klass) {
6779 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6781 byte_array_klass = klass;
6783 klass = mono_array_class_get (mono_defaults.string_class, 1);
6785 string_array_klass = klass;
6787 klass = mono_array_class_get (mono_defaults.object_class, 1);
6790 mono_atomic_store_release (&object_array_klass, klass);
6793 MONO_OBJECT_SETREF (this_obj, method, method);
6795 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, &error);
6796 mono_error_raise_exception (&error); /* FIXME don't raise here */
6798 MONO_OBJECT_SETREF (this_obj, args, arr);
6800 arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, &error);
6801 mono_error_raise_exception (&error); /* FIXME don't raise here */
6803 MONO_OBJECT_SETREF (this_obj, arg_types, arr);
6805 this_obj->async_result = NULL;
6806 this_obj->call_type = CallType_Sync;
6808 names = g_new (char *, sig->param_count);
6809 mono_method_get_param_names (method->method, (const char **) names);
6811 arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, &error);
6812 mono_error_raise_exception (&error); /* FIXME don't raise here */
6814 MONO_OBJECT_SETREF (this_obj, names, arr);
6816 for (i = 0; i < sig->param_count; i++) {
6817 name = mono_string_new (domain, names [i]);
6818 mono_array_setref (this_obj->names, i, name);
6822 for (i = 0, j = 0; i < sig->param_count; i++) {
6823 if (sig->params [i]->byref) {
6825 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
6826 mono_array_setref (this_obj->args, i, arg);
6830 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6834 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6837 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
6841 #ifndef DISABLE_REMOTING
6843 * mono_remoting_invoke:
6844 * @real_proxy: pointer to a RealProxy object
6845 * @msg: The MonoMethodMessage to execute
6846 * @exc: used to store exceptions
6847 * @out_args: used to store output arguments
6849 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6850 * IMessage interface and it is not trivial to extract results from there. So
6851 * we call an helper method PrivateInvoke instead of calling
6852 * RealProxy::Invoke() directly.
6854 * Returns: the result object.
6857 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
6859 MONO_REQ_GC_UNSAFE_MODE;
6862 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6867 mono_error_init (error);
6869 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6872 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6874 mono_error_set_generic_error (error, "System", "NotSupportedException", "Linked away.");
6877 real_proxy->vtable->domain->private_invoke_method = im;
6880 pa [0] = real_proxy;
6885 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
6886 return_val_if_nok (error, NULL);
6893 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6894 MonoObject **exc, MonoArray **out_args)
6896 MONO_REQ_GC_UNSAFE_MODE;
6898 static MonoClass *object_array_klass;
6902 MonoMethodSignature *sig;
6905 int i, j, outarg_count = 0;
6907 #ifndef DISABLE_REMOTING
6908 if (target && mono_object_is_transparent_proxy (target)) {
6909 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6910 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6911 target = tp->rp->unwrapped_server;
6913 ret = mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, &error);
6914 mono_error_raise_exception (&error); /* FIXME don't raise here */
6921 domain = mono_domain_get ();
6922 method = msg->method->method;
6923 sig = mono_method_signature (method);
6925 for (i = 0; i < sig->param_count; i++) {
6926 if (sig->params [i]->byref)
6930 if (!object_array_klass) {
6933 klass = mono_array_class_get (mono_defaults.object_class, 1);
6936 mono_memory_barrier ();
6937 object_array_klass = klass;
6940 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, &error);
6941 mono_error_raise_exception (&error); /* FIXME don't raise here */
6943 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
6946 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6948 for (i = 0, j = 0; i < sig->param_count; i++) {
6949 if (sig->params [i]->byref) {
6951 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
6952 mono_array_setref (*out_args, j, arg);
6961 * mono_object_to_string:
6963 * @exc: Any exception thrown by ToString (). May be NULL.
6965 * Returns: the result of calling ToString () on an object.
6968 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6970 MONO_REQ_GC_UNSAFE_MODE;
6972 static MonoMethod *to_string = NULL;
6981 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6983 method = mono_object_get_virtual_method (obj, to_string);
6985 // Unbox value type if needed
6986 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6987 target = mono_object_unbox (obj);
6991 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
6992 if (*exc == NULL && !mono_error_ok (&error))
6993 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
6995 mono_error_cleanup (&error);
6997 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
6998 mono_error_raise_exception (&error); /* FIXME don't raise here */
7005 * mono_print_unhandled_exception:
7006 * @exc: The exception
7008 * Prints the unhandled exception.
7011 mono_print_unhandled_exception (MonoObject *exc)
7013 MONO_REQ_GC_UNSAFE_MODE;
7016 char *message = (char*)"";
7017 gboolean free_message = FALSE;
7020 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7021 message = g_strdup ("OutOfMemoryException");
7022 free_message = TRUE;
7023 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7024 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7025 free_message = TRUE;
7028 if (((MonoException*)exc)->native_trace_ips) {
7029 message = mono_exception_get_native_backtrace ((MonoException*)exc);
7030 free_message = TRUE;
7032 MonoObject *other_exc = NULL;
7033 str = mono_object_to_string (exc, &other_exc);
7035 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7036 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7038 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7039 original_backtrace, nested_backtrace);
7041 g_free (original_backtrace);
7042 g_free (nested_backtrace);
7043 free_message = TRUE;
7045 message = mono_string_to_utf8_checked (str, &error);
7046 if (!mono_error_ok (&error)) {
7047 mono_error_cleanup (&error);
7048 message = (char *) "";
7050 free_message = TRUE;
7057 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7058 * exc->vtable->klass->name, message);
7060 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7067 * mono_delegate_ctor:
7068 * @this: pointer to an uninitialized delegate object
7069 * @target: target object
7070 * @addr: pointer to native code
7073 * Initialize a delegate and sets a specific method, not the one
7074 * associated with addr. This is useful when sharing generic code.
7075 * In that case addr will most probably not be associated with the
7076 * correct instantiation of the method.
7079 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
7081 MONO_REQ_GC_UNSAFE_MODE;
7083 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7085 g_assert (this_obj);
7088 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7091 delegate->method = method;
7093 mono_stats.delegate_creations++;
7095 #ifndef DISABLE_REMOTING
7096 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7098 method = mono_marshal_get_remoting_invoke (method);
7099 delegate->method_ptr = mono_compile_method (method);
7100 MONO_OBJECT_SETREF (delegate, target, target);
7104 delegate->method_ptr = addr;
7105 MONO_OBJECT_SETREF (delegate, target, target);
7108 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7109 if (callbacks.init_delegate)
7110 callbacks.init_delegate (delegate);
7114 * mono_delegate_ctor:
7115 * @this: pointer to an uninitialized delegate object
7116 * @target: target object
7117 * @addr: pointer to native code
7119 * This is used to initialize a delegate.
7122 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
7124 MONO_REQ_GC_UNSAFE_MODE;
7126 MonoDomain *domain = mono_domain_get ();
7128 MonoMethod *method = NULL;
7132 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7134 if (!ji && domain != mono_get_root_domain ())
7135 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7137 method = mono_jit_info_get_method (ji);
7138 g_assert (!method->klass->generic_container);
7141 mono_delegate_ctor_with_method (this_obj, target, addr, method);
7145 * mono_method_call_message_new:
7146 * @method: method to encapsulate
7147 * @params: parameters to the method
7148 * @invoke: optional, delegate invoke.
7149 * @cb: async callback delegate.
7150 * @state: state passed to the async callback.
7152 * Translates arguments pointers into a MonoMethodMessage.
7155 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7156 MonoDelegate **cb, MonoObject **state)
7158 MONO_REQ_GC_UNSAFE_MODE;
7162 MonoDomain *domain = mono_domain_get ();
7163 MonoMethodSignature *sig = mono_method_signature (method);
7164 MonoMethodMessage *msg;
7167 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7168 mono_error_raise_exception (&error); /* FIXME don't raise here */
7171 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, &error);
7172 mono_error_raise_exception (&error); /* FIXME don't raise here */
7173 mono_message_init (domain, msg, rm, NULL);
7174 count = sig->param_count - 2;
7176 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, &error);
7177 mono_error_raise_exception (&error); /* FIXME don't raise here */
7178 mono_message_init (domain, msg, rm, NULL);
7179 count = sig->param_count;
7182 for (i = 0; i < count; i++) {
7187 if (sig->params [i]->byref)
7188 vpos = *((gpointer *)params [i]);
7192 klass = mono_class_from_mono_type (sig->params [i]);
7194 if (klass->valuetype)
7195 arg = mono_value_box (domain, klass, vpos);
7197 arg = *((MonoObject **)vpos);
7199 mono_array_setref (msg->args, i, arg);
7202 if (cb != NULL && state != NULL) {
7203 *cb = *((MonoDelegate **)params [i]);
7205 *state = *((MonoObject **)params [i]);
7212 * mono_method_return_message_restore:
7214 * Restore results from message based processing back to arguments pointers
7217 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
7219 MONO_REQ_GC_UNSAFE_MODE;
7221 MonoMethodSignature *sig = mono_method_signature (method);
7222 int i, j, type, size, out_len;
7224 if (out_args == NULL)
7226 out_len = mono_array_length (out_args);
7230 for (i = 0, j = 0; i < sig->param_count; i++) {
7231 MonoType *pt = sig->params [i];
7236 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
7238 arg = (char *)mono_array_get (out_args, gpointer, j);
7241 g_assert (type != MONO_TYPE_VOID);
7243 if (MONO_TYPE_IS_REFERENCE (pt)) {
7244 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7247 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7248 size = mono_class_value_size (klass, NULL);
7249 if (klass->has_references)
7250 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7252 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7254 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7255 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7264 #ifndef DISABLE_REMOTING
7267 * mono_load_remote_field:
7268 * @this: pointer to an object
7269 * @klass: klass of the object containing @field
7270 * @field: the field to load
7271 * @res: a storage to store the result
7273 * This method is called by the runtime on attempts to load fields of
7274 * transparent proxy objects. @this points to such TP, @klass is the class of
7275 * the object containing @field. @res is a storage location which can be
7276 * used to store the result.
7278 * Returns: an address pointing to the value of field.
7281 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
7283 MONO_REQ_GC_UNSAFE_MODE;
7287 static MonoMethod *getter = NULL;
7288 MonoDomain *domain = mono_domain_get ();
7289 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7290 MonoClass *field_class;
7291 MonoMethodMessage *msg;
7292 MonoArray *out_args;
7296 g_assert (mono_object_is_transparent_proxy (this_obj));
7297 g_assert (res != NULL);
7299 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7300 mono_field_get_value (tp->rp->unwrapped_server, field, res);
7305 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7307 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7310 field_class = mono_class_from_mono_type (field->type);
7312 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7313 mono_error_raise_exception (&error); /* FIXME don't raise here */
7314 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7315 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7316 mono_error_raise_exception (&error); /* FIXME don't raise here */
7317 mono_message_init (domain, msg, rm, out_args);
7319 full_name = mono_type_get_full_name (klass);
7320 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7321 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7324 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, &error);
7325 mono_error_raise_exception (&error); /* FIXME don't raise here */
7327 if (exc) mono_raise_exception ((MonoException *)exc);
7329 if (mono_array_length (out_args) == 0)
7332 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
7334 if (field_class->valuetype) {
7335 return ((char *)*res) + sizeof (MonoObject);
7341 * mono_load_remote_field_new:
7346 * Missing documentation.
7349 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
7351 MONO_REQ_GC_UNSAFE_MODE;
7355 static MonoMethod *getter = NULL;
7356 MonoDomain *domain = mono_domain_get ();
7357 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7358 MonoClass *field_class;
7359 MonoMethodMessage *msg;
7360 MonoArray *out_args;
7361 MonoObject *exc, *res;
7364 g_assert (mono_object_is_transparent_proxy (this_obj));
7366 field_class = mono_class_from_mono_type (field->type);
7368 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7370 if (field_class->valuetype) {
7371 res = mono_object_new_checked (domain, field_class, &error);
7372 mono_error_raise_exception (&error); /* FIXME don't raise here */
7373 val = ((gchar *) res) + sizeof (MonoObject);
7377 mono_field_get_value (tp->rp->unwrapped_server, field, val);
7382 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7384 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7387 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7388 mono_error_raise_exception (&error); /* FIXME don't raise here */
7389 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7391 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7392 mono_error_raise_exception (&error); /* FIXME don't raise here */
7393 mono_message_init (domain, msg, rm, out_args);
7395 full_name = mono_type_get_full_name (klass);
7396 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7397 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7400 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, &error);
7401 mono_error_raise_exception (&error); /* FIXME don't raise here */
7403 if (exc) mono_raise_exception ((MonoException *)exc);
7405 if (mono_array_length (out_args) == 0)
7408 res = mono_array_get (out_args, MonoObject *, 0);
7414 * mono_store_remote_field:
7415 * @this_obj: pointer to an object
7416 * @klass: klass of the object containing @field
7417 * @field: the field to load
7418 * @val: the value/object to store
7420 * This method is called by the runtime on attempts to store fields of
7421 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
7422 * the object containing @field. @val is the new value to store in @field.
7425 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
7427 MONO_REQ_GC_UNSAFE_MODE;
7431 static MonoMethod *setter = NULL;
7432 MonoDomain *domain = mono_domain_get ();
7433 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7434 MonoClass *field_class;
7435 MonoMethodMessage *msg;
7436 MonoArray *out_args;
7441 g_assert (mono_object_is_transparent_proxy (this_obj));
7443 field_class = mono_class_from_mono_type (field->type);
7445 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7446 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
7447 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
7452 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7454 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7457 if (field_class->valuetype)
7458 arg = mono_value_box (domain, field_class, val);
7460 arg = *((MonoObject **)val);
7463 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7464 mono_error_raise_exception (&error); /* FIXME don't raise here */
7465 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7466 mono_error_raise_exception (&error); /* FIXME don't raise here */
7467 mono_message_init (domain, msg, rm, NULL);
7469 full_name = mono_type_get_full_name (klass);
7470 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7471 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7472 mono_array_setref (msg->args, 2, arg);
7475 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, &error);
7476 mono_error_raise_exception (&error); /* FIXME don't raise here */
7478 if (exc) mono_raise_exception ((MonoException *)exc);
7482 * mono_store_remote_field_new:
7488 * Missing documentation
7491 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
7493 MONO_REQ_GC_UNSAFE_MODE;
7497 static MonoMethod *setter = NULL;
7498 MonoDomain *domain = mono_domain_get ();
7499 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7500 MonoClass *field_class;
7501 MonoMethodMessage *msg;
7502 MonoArray *out_args;
7506 g_assert (mono_object_is_transparent_proxy (this_obj));
7508 field_class = mono_class_from_mono_type (field->type);
7510 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7511 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
7512 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
7517 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7519 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7522 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7523 mono_error_raise_exception (&error); /* FIXME don't raise here */
7524 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7525 mono_error_raise_exception (&error); /* FIXME don't raise here */
7526 mono_message_init (domain, msg, rm, NULL);
7528 full_name = mono_type_get_full_name (klass);
7529 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7530 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7531 mono_array_setref (msg->args, 2, arg);
7534 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, &error);
7535 mono_error_raise_exception (&error); /* FIXME don't raise here */
7537 if (exc) mono_raise_exception ((MonoException *)exc);
7542 * mono_create_ftnptr:
7544 * Given a function address, create a function descriptor for it.
7545 * This is only needed on some platforms.
7548 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
7550 return callbacks.create_ftnptr (domain, addr);
7554 * mono_get_addr_from_ftnptr:
7556 * Given a pointer to a function descriptor, return the function address.
7557 * This is only needed on some platforms.
7560 mono_get_addr_from_ftnptr (gpointer descr)
7562 return callbacks.get_addr_from_ftnptr (descr);
7566 * mono_string_chars:
7569 * Returns a pointer to the UCS16 characters stored in the MonoString
7572 mono_string_chars (MonoString *s)
7574 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
7580 * mono_string_length:
7583 * Returns the lenght in characters of the string
7586 mono_string_length (MonoString *s)
7588 MONO_REQ_GC_UNSAFE_MODE;
7594 * mono_array_length:
7595 * @array: a MonoArray*
7597 * Returns the total number of elements in the array. This works for
7598 * both vectors and multidimensional arrays.
7601 mono_array_length (MonoArray *array)
7603 MONO_REQ_GC_UNSAFE_MODE;
7605 return array->max_length;
7609 * mono_array_addr_with_size:
7610 * @array: a MonoArray*
7611 * @size: size of the array elements
7612 * @idx: index into the array
7614 * Use this function to obtain the address for the @idx item on the
7615 * @array containing elements of size @size.
7617 * This method performs no bounds checking or type checking.
7619 * Returns the address of the @idx element in the array.
7622 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
7624 MONO_REQ_GC_UNSAFE_MODE;
7626 return ((char*)(array)->vector) + size * idx;
7631 mono_glist_to_array (GList *list, MonoClass *eclass)
7633 MonoDomain *domain = mono_domain_get ();
7640 len = g_list_length (list);
7641 res = mono_array_new (domain, eclass, len);
7643 for (i = 0; list; list = list->next, i++)
7644 mono_array_set (res, gpointer, i, list->data);
7651 * The following section is purely to declare prototypes and
7652 * document the API, as these C files are processed by our
7658 * @array: array to alter
7659 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
7660 * @index: index into the array
7661 * @value: value to set
7663 * Value Type version: This sets the @index's element of the @array
7664 * with elements of size sizeof(type) to the provided @value.
7666 * This macro does not attempt to perform type checking or bounds checking.
7668 * Use this to set value types in a `MonoArray`.
7670 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
7675 * mono_array_setref:
7676 * @array: array to alter
7677 * @index: index into the array
7678 * @value: value to set
7680 * Reference Type version: This sets the @index's element of the
7681 * @array with elements of size sizeof(type) to the provided @value.
7683 * This macro does not attempt to perform type checking or bounds checking.
7685 * Use this to reference types in a `MonoArray`.
7687 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
7693 * @array: array on which to operate on
7694 * @element_type: C element type (example: MonoString *, int, MonoObject *)
7695 * @index: index into the array
7697 * Use this macro to retrieve the @index element of an @array and
7698 * extract the value assuming that the elements of the array match
7699 * the provided type value.
7701 * This method can be used with both arrays holding value types and
7702 * reference types. For reference types, the @type parameter should
7703 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
7705 * This macro does not attempt to perform type checking or bounds checking.
7707 * Returns: The element at the @index position in the @array.
7709 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)