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 if (!is_ok (error)) {
2167 mono_domain_unlock (domain);
2168 mono_loader_unlock ();
2175 if (imt_table_bytes) {
2176 /* Now that the vtable is full, we can actually fill up the IMT */
2177 for (i = 0; i < MONO_IMT_SIZE; ++i)
2178 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2182 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2183 * re-acquire them and check if another thread has created the vtable in the meantime.
2185 /* Special case System.MonoType to avoid infinite recursion */
2186 if (klass != mono_defaults.monotype_class) {
2187 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2188 if (!is_ok (error)) {
2189 mono_domain_unlock (domain);
2190 mono_loader_unlock ();
2194 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2195 /* This is unregistered in
2196 unregister_vtable_reflection_type() in
2198 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2201 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2203 /* class_vtable_array keeps an array of created vtables
2205 g_ptr_array_add (domain->class_vtable_array, vt);
2206 /* klass->runtime_info is protected by the loader lock, both when
2207 * it it enlarged and when it is stored info.
2211 * Store the vtable in klass->runtime_info.
2212 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2214 mono_memory_barrier ();
2216 old_info = klass->runtime_info;
2217 if (old_info && old_info->max_domain >= domain->domain_id) {
2218 /* someone already created a large enough runtime info */
2219 old_info->domain_vtables [domain->domain_id] = vt;
2221 int new_size = domain->domain_id;
2223 new_size = MAX (new_size, old_info->max_domain);
2225 /* make the new size a power of two */
2227 while (new_size > i)
2230 /* this is a bounded memory retention issue: may want to
2231 * handle it differently when we'll have a rcu-like system.
2233 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2234 runtime_info->max_domain = new_size - 1;
2235 /* copy the stuff from the older info */
2237 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2239 runtime_info->domain_vtables [domain->domain_id] = vt;
2241 mono_memory_barrier ();
2242 klass->runtime_info = runtime_info;
2245 if (klass == mono_defaults.monotype_class) {
2246 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2247 if (!is_ok (error)) {
2248 mono_domain_unlock (domain);
2249 mono_loader_unlock ();
2253 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2254 /* This is unregistered in
2255 unregister_vtable_reflection_type() in
2257 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2260 mono_domain_unlock (domain);
2261 mono_loader_unlock ();
2263 /* make sure the parent is initialized */
2264 /*FIXME shouldn't this fail the current type?*/
2266 mono_class_vtable_full (domain, klass->parent, error);
2271 #ifndef DISABLE_REMOTING
2273 * mono_class_proxy_vtable:
2274 * @domain: the application domain
2275 * @remove_class: the remote class
2277 * Creates a vtable for transparent proxies. It is basically
2278 * a copy of the real vtable of the class wrapped in @remote_class,
2279 * but all function pointers invoke the remoting functions, and
2280 * vtable->klass points to the transparent proxy class, and not to @class.
2283 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2285 MONO_REQ_GC_UNSAFE_MODE;
2288 MonoVTable *vt, *pvt;
2289 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2291 GSList *extra_interfaces = NULL;
2292 MonoClass *klass = remote_class->proxy_class;
2293 gpointer *interface_offsets;
2296 size_t imt_table_bytes;
2298 #ifdef COMPRESSED_INTERFACE_BITMAP
2302 vt = mono_class_vtable (domain, klass);
2303 g_assert (vt); /*FIXME property handle failure*/
2304 max_interface_id = vt->max_interface_id;
2306 /* Calculate vtable space for extra interfaces */
2307 for (j = 0; j < remote_class->interface_count; j++) {
2308 MonoClass* iclass = remote_class->interfaces[j];
2312 /*FIXME test for interfaces with variant generic arguments*/
2313 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2314 continue; /* interface implemented by the class */
2315 if (g_slist_find (extra_interfaces, iclass))
2318 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2320 method_count = mono_class_num_methods (iclass);
2322 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2323 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2325 for (i = 0; i < ifaces->len; ++i) {
2326 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2327 /*FIXME test for interfaces with variant generic arguments*/
2328 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2329 continue; /* interface implemented by the class */
2330 if (g_slist_find (extra_interfaces, ic))
2332 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2333 method_count += mono_class_num_methods (ic);
2335 g_ptr_array_free (ifaces, TRUE);
2338 extra_interface_vtsize += method_count * sizeof (gpointer);
2339 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2342 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2343 mono_stats.imt_number_of_tables++;
2344 mono_stats.imt_tables_size += imt_table_bytes;
2346 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2348 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2350 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2351 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2352 g_assert (!((gsize)pvt & 7));
2354 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2356 pvt->klass = mono_defaults.transparent_proxy_class;
2357 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2358 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2360 /* initialize vtable */
2361 mono_class_setup_vtable (klass);
2362 for (i = 0; i < klass->vtable_size; ++i) {
2365 if ((cm = klass->vtable [i]))
2366 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2368 pvt->vtable [i] = NULL;
2371 if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2372 /* create trampolines for abstract methods */
2373 for (k = klass; k; k = k->parent) {
2375 gpointer iter = NULL;
2376 while ((m = mono_class_get_methods (k, &iter)))
2377 if (!pvt->vtable [m->slot])
2378 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2382 pvt->max_interface_id = max_interface_id;
2383 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2384 #ifdef COMPRESSED_INTERFACE_BITMAP
2385 bitmap = (uint8_t *)g_malloc0 (bsize);
2387 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2390 for (i = 0; i < klass->interface_offsets_count; ++i) {
2391 int interface_id = klass->interfaces_packed [i]->interface_id;
2392 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2395 if (extra_interfaces) {
2396 int slot = klass->vtable_size;
2402 /* Create trampolines for the methods of the interfaces */
2403 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2404 interf = (MonoClass *)list_item->data;
2406 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2410 while ((cm = mono_class_get_methods (interf, &iter)))
2411 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2413 slot += mono_class_num_methods (interf);
2417 /* Now that the vtable is full, we can actually fill up the IMT */
2418 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2419 if (extra_interfaces) {
2420 g_slist_free (extra_interfaces);
2423 #ifdef COMPRESSED_INTERFACE_BITMAP
2424 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2425 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2426 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2429 pvt->interface_bitmap = bitmap;
2434 #endif /* DISABLE_REMOTING */
2437 * mono_class_field_is_special_static:
2439 * Returns whether @field is a thread/context static field.
2442 mono_class_field_is_special_static (MonoClassField *field)
2444 MONO_REQ_GC_NEUTRAL_MODE
2446 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2448 if (mono_field_is_deleted (field))
2450 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2451 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2458 * mono_class_field_get_special_static_type:
2459 * @field: The MonoClassField describing the field.
2461 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2462 * SPECIAL_STATIC_NONE otherwise.
2465 mono_class_field_get_special_static_type (MonoClassField *field)
2467 MONO_REQ_GC_NEUTRAL_MODE
2469 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2470 return SPECIAL_STATIC_NONE;
2471 if (mono_field_is_deleted (field))
2472 return SPECIAL_STATIC_NONE;
2473 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2474 return field_is_special_static (field->parent, field);
2475 return SPECIAL_STATIC_NONE;
2479 * mono_class_has_special_static_fields:
2481 * Returns whenever @klass has any thread/context static fields.
2484 mono_class_has_special_static_fields (MonoClass *klass)
2486 MONO_REQ_GC_NEUTRAL_MODE
2488 MonoClassField *field;
2492 while ((field = mono_class_get_fields (klass, &iter))) {
2493 g_assert (field->parent == klass);
2494 if (mono_class_field_is_special_static (field))
2501 #ifndef DISABLE_REMOTING
2503 * create_remote_class_key:
2504 * Creates an array of pointers that can be used as a hash key for a remote class.
2505 * The first element of the array is the number of pointers.
2508 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2510 MONO_REQ_GC_NEUTRAL_MODE;
2515 if (remote_class == NULL) {
2516 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2517 key = (void **)g_malloc (sizeof(gpointer) * 3);
2518 key [0] = GINT_TO_POINTER (2);
2519 key [1] = mono_defaults.marshalbyrefobject_class;
2520 key [2] = extra_class;
2522 key = (void **)g_malloc (sizeof(gpointer) * 2);
2523 key [0] = GINT_TO_POINTER (1);
2524 key [1] = extra_class;
2527 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2528 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2529 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2530 key [1] = remote_class->proxy_class;
2532 // Keep the list of interfaces sorted
2533 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2534 if (extra_class && remote_class->interfaces [i] > extra_class) {
2535 key [j++] = extra_class;
2538 key [j] = remote_class->interfaces [i];
2541 key [j] = extra_class;
2543 // Replace the old class. The interface list is the same
2544 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2545 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2546 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2547 for (i = 0; i < remote_class->interface_count; i++)
2548 key [2 + i] = remote_class->interfaces [i];
2556 * copy_remote_class_key:
2558 * Make a copy of KEY in the domain and return the copy.
2561 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2563 MONO_REQ_GC_NEUTRAL_MODE
2565 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2566 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2568 memcpy (mp_key, key, key_size);
2574 * mono_remote_class:
2575 * @domain: the application domain
2576 * @class_name: name of the remote class
2578 * Creates and initializes a MonoRemoteClass object for a remote type.
2580 * Can raise an exception on failure.
2583 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2585 MONO_REQ_GC_UNSAFE_MODE;
2588 MonoRemoteClass *rc;
2589 gpointer* key, *mp_key;
2592 key = create_remote_class_key (NULL, proxy_class);
2594 mono_domain_lock (domain);
2595 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2599 mono_domain_unlock (domain);
2603 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2604 if (!mono_error_ok (&error)) {
2606 mono_domain_unlock (domain);
2607 mono_error_raise_exception (&error);
2610 mp_key = copy_remote_class_key (domain, key);
2614 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2615 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2616 rc->interface_count = 1;
2617 rc->interfaces [0] = proxy_class;
2618 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2620 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2621 rc->interface_count = 0;
2622 rc->proxy_class = proxy_class;
2625 rc->default_vtable = NULL;
2626 rc->xdomain_vtable = NULL;
2627 rc->proxy_class_name = name;
2628 #ifndef DISABLE_PERFCOUNTERS
2629 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2632 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2634 mono_domain_unlock (domain);
2639 * clone_remote_class:
2640 * Creates a copy of the remote_class, adding the provided class or interface
2642 static MonoRemoteClass*
2643 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2645 MONO_REQ_GC_NEUTRAL_MODE;
2647 MonoRemoteClass *rc;
2648 gpointer* key, *mp_key;
2650 key = create_remote_class_key (remote_class, extra_class);
2651 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2657 mp_key = copy_remote_class_key (domain, key);
2661 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2663 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2664 rc->proxy_class = remote_class->proxy_class;
2665 rc->interface_count = remote_class->interface_count + 1;
2667 // Keep the list of interfaces sorted, since the hash key of
2668 // the remote class depends on this
2669 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2670 if (remote_class->interfaces [i] > extra_class && i == j)
2671 rc->interfaces [j++] = extra_class;
2672 rc->interfaces [j] = remote_class->interfaces [i];
2675 rc->interfaces [j] = extra_class;
2677 // Replace the old class. The interface array is the same
2678 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2679 rc->proxy_class = extra_class;
2680 rc->interface_count = remote_class->interface_count;
2681 if (rc->interface_count > 0)
2682 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2685 rc->default_vtable = NULL;
2686 rc->xdomain_vtable = NULL;
2687 rc->proxy_class_name = remote_class->proxy_class_name;
2689 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2695 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2697 MONO_REQ_GC_UNSAFE_MODE;
2699 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2700 mono_domain_lock (domain);
2701 if (rp->target_domain_id != -1) {
2702 if (remote_class->xdomain_vtable == NULL)
2703 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2704 mono_domain_unlock (domain);
2705 mono_loader_unlock ();
2706 return remote_class->xdomain_vtable;
2708 if (remote_class->default_vtable == NULL) {
2711 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2712 klass = mono_class_from_mono_type (type);
2714 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)))
2715 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2718 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2721 mono_domain_unlock (domain);
2722 mono_loader_unlock ();
2723 return remote_class->default_vtable;
2727 * mono_upgrade_remote_class:
2728 * @domain: the application domain
2729 * @tproxy: the proxy whose remote class has to be upgraded.
2730 * @klass: class to which the remote class can be casted.
2732 * Updates the vtable of the remote class by adding the necessary method slots
2733 * and interface offsets so it can be safely casted to klass. klass can be a
2734 * class or an interface.
2737 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2739 MONO_REQ_GC_UNSAFE_MODE;
2741 MonoTransparentProxy *tproxy;
2742 MonoRemoteClass *remote_class;
2743 gboolean redo_vtable;
2745 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2746 mono_domain_lock (domain);
2748 tproxy = (MonoTransparentProxy*) proxy_object;
2749 remote_class = tproxy->remote_class;
2751 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2754 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2755 if (remote_class->interfaces [i] == klass)
2756 redo_vtable = FALSE;
2759 redo_vtable = (remote_class->proxy_class != klass);
2763 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2764 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2767 mono_domain_unlock (domain);
2768 mono_loader_unlock ();
2770 #endif /* DISABLE_REMOTING */
2774 * mono_object_get_virtual_method:
2775 * @obj: object to operate on.
2778 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2779 * the instance of a callvirt of method.
2782 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2784 MONO_REQ_GC_UNSAFE_MODE;
2787 MonoMethod **vtable;
2788 gboolean is_proxy = FALSE;
2789 MonoMethod *res = NULL;
2791 klass = mono_object_class (obj);
2792 #ifndef DISABLE_REMOTING
2793 if (klass == mono_defaults.transparent_proxy_class) {
2794 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2799 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2802 mono_class_setup_vtable (klass);
2803 vtable = klass->vtable;
2805 if (method->slot == -1) {
2806 /* method->slot might not be set for instances of generic methods */
2807 if (method->is_inflated) {
2808 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2809 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2812 g_assert_not_reached ();
2816 /* check method->slot is a valid index: perform isinstance? */
2817 if (method->slot != -1) {
2818 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2820 gboolean variance_used = FALSE;
2821 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2822 g_assert (iface_offset > 0);
2823 res = vtable [iface_offset + method->slot];
2826 res = vtable [method->slot];
2830 #ifndef DISABLE_REMOTING
2832 /* It may be an interface, abstract class method or generic method */
2833 if (!res || mono_method_signature (res)->generic_param_count)
2836 /* generic methods demand invoke_with_check */
2837 if (mono_method_signature (res)->generic_param_count)
2838 res = mono_marshal_get_remoting_invoke_with_check (res);
2841 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2842 res = mono_cominterop_get_invoke (res);
2845 res = mono_marshal_get_remoting_invoke (res);
2850 if (method->is_inflated) {
2852 /* Have to inflate the result */
2853 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2854 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2864 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2866 MONO_REQ_GC_UNSAFE_MODE;
2868 MonoObject *result = NULL;
2870 g_assert (callbacks.runtime_invoke);
2872 mono_error_init (error);
2874 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2875 mono_profiler_method_start_invoke (method);
2877 MONO_PREPARE_RESET_BLOCKING;
2879 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2881 MONO_FINISH_RESET_BLOCKING;
2883 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2884 mono_profiler_method_end_invoke (method);
2886 if (!mono_error_ok (error))
2893 * mono_runtime_invoke:
2894 * @method: method to invoke
2895 * @obJ: object instance
2896 * @params: arguments to the method
2897 * @exc: exception information.
2899 * Invokes the method represented by @method on the object @obj.
2901 * obj is the 'this' pointer, it should be NULL for static
2902 * methods, a MonoObject* for object instances and a pointer to
2903 * the value type for value types.
2905 * The params array contains the arguments to the method with the
2906 * same convention: MonoObject* pointers for object instances and
2907 * pointers to the value type otherwise.
2909 * From unmanaged code you'll usually use the
2910 * mono_runtime_invoke() variant.
2912 * Note that this function doesn't handle virtual methods for
2913 * you, it will exec the exact method you pass: we still need to
2914 * expose a function to lookup the derived class implementation
2915 * of a virtual method (there are examples of this in the code,
2918 * You can pass NULL as the exc argument if you don't want to
2919 * catch exceptions, otherwise, *exc will be set to the exception
2920 * thrown, if any. if an exception is thrown, you can't use the
2921 * MonoObject* result from the function.
2923 * If the method returns a value type, it is boxed in an object
2927 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2932 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2933 if (*exc == NULL && !mono_error_ok(&error)) {
2934 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2936 mono_error_cleanup (&error);
2938 res = mono_runtime_invoke_checked (method, obj, params, &error);
2939 mono_error_raise_exception (&error);
2945 * mono_runtime_try_invoke:
2946 * @method: method to invoke
2947 * @obJ: object instance
2948 * @params: arguments to the method
2949 * @exc: exception information.
2950 * @error: set on error
2952 * Invokes the method represented by @method on the object @obj.
2954 * obj is the 'this' pointer, it should be NULL for static
2955 * methods, a MonoObject* for object instances and a pointer to
2956 * the value type for value types.
2958 * The params array contains the arguments to the method with the
2959 * same convention: MonoObject* pointers for object instances and
2960 * pointers to the value type otherwise.
2962 * From unmanaged code you'll usually use the
2963 * mono_runtime_invoke() variant.
2965 * Note that this function doesn't handle virtual methods for
2966 * you, it will exec the exact method you pass: we still need to
2967 * expose a function to lookup the derived class implementation
2968 * of a virtual method (there are examples of this in the code,
2971 * For this function, you must not pass NULL as the exc argument if
2972 * you don't want to catch exceptions, use
2973 * mono_runtime_invoke_checked(). If an exception is thrown, you
2974 * can't use the MonoObject* result from the function.
2976 * If this method cannot be invoked, @error will be set and @exc and
2977 * the return value must not be used.
2979 * If the method returns a value type, it is boxed in an object
2983 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2985 MONO_REQ_GC_UNSAFE_MODE;
2987 g_assert (exc != NULL);
2989 if (mono_runtime_get_no_exec ())
2990 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2992 return do_runtime_invoke (method, obj, params, exc, error);
2996 * mono_runtime_invoke_checked:
2997 * @method: method to invoke
2998 * @obJ: object instance
2999 * @params: arguments to the method
3000 * @error: set on error
3002 * Invokes the method represented by @method on the object @obj.
3004 * obj is the 'this' pointer, it should be NULL for static
3005 * methods, a MonoObject* for object instances and a pointer to
3006 * the value type for value types.
3008 * The params array contains the arguments to the method with the
3009 * same convention: MonoObject* pointers for object instances and
3010 * pointers to the value type otherwise.
3012 * From unmanaged code you'll usually use the
3013 * mono_runtime_invoke() variant.
3015 * Note that this function doesn't handle virtual methods for
3016 * you, it will exec the exact method you pass: we still need to
3017 * expose a function to lookup the derived class implementation
3018 * of a virtual method (there are examples of this in the code,
3021 * If an exception is thrown, you can't use the MonoObject* result
3022 * from the function.
3024 * If this method cannot be invoked, @error will be set. If the
3025 * method throws an exception (and we're in coop mode) the exception
3026 * will be set in @error.
3028 * If the method returns a value type, it is boxed in an object
3032 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3034 MONO_REQ_GC_UNSAFE_MODE;
3036 if (mono_runtime_get_no_exec ())
3037 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3039 return do_runtime_invoke (method, obj, params, NULL, error);
3043 * mono_method_get_unmanaged_thunk:
3044 * @method: method to generate a thunk for.
3046 * Returns an unmanaged->managed thunk that can be used to call
3047 * a managed method directly from C.
3049 * The thunk's C signature closely matches the managed signature:
3051 * C#: public bool Equals (object obj);
3052 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3053 * MonoObject*, MonoException**);
3055 * The 1st ("this") parameter must not be used with static methods:
3057 * C#: public static bool ReferenceEquals (object a, object b);
3058 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3061 * The last argument must be a non-null pointer of a MonoException* pointer.
3062 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3063 * exception has been thrown in managed code. Otherwise it will point
3064 * to the MonoException* caught by the thunk. In this case, the result of
3065 * the thunk is undefined:
3067 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3068 * MonoException *ex = NULL;
3069 * Equals func = mono_method_get_unmanaged_thunk (method);
3070 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3072 * // handle exception
3075 * The calling convention of the thunk matches the platform's default
3076 * convention. This means that under Windows, C declarations must
3077 * contain the __stdcall attribute:
3079 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3080 * MonoObject*, MonoException**);
3084 * Value type arguments and return values are treated as they were objects:
3086 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3087 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3089 * Arguments must be properly boxed upon trunk's invocation, while return
3090 * values must be unboxed.
3093 mono_method_get_unmanaged_thunk (MonoMethod *method)
3095 MONO_REQ_GC_NEUTRAL_MODE;
3096 MONO_REQ_API_ENTRYPOINT;
3100 MONO_PREPARE_RESET_BLOCKING;
3101 method = mono_marshal_get_thunk_invoke_wrapper (method);
3102 res = mono_compile_method (method);
3103 MONO_FINISH_RESET_BLOCKING;
3109 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3111 MONO_REQ_GC_UNSAFE_MODE;
3115 /* object fields cannot be byref, so we don't need a
3117 gpointer *p = (gpointer*)dest;
3124 case MONO_TYPE_BOOLEAN:
3126 case MONO_TYPE_U1: {
3127 guint8 *p = (guint8*)dest;
3128 *p = value ? *(guint8*)value : 0;
3133 case MONO_TYPE_CHAR: {
3134 guint16 *p = (guint16*)dest;
3135 *p = value ? *(guint16*)value : 0;
3138 #if SIZEOF_VOID_P == 4
3143 case MONO_TYPE_U4: {
3144 gint32 *p = (gint32*)dest;
3145 *p = value ? *(gint32*)value : 0;
3148 #if SIZEOF_VOID_P == 8
3153 case MONO_TYPE_U8: {
3154 gint64 *p = (gint64*)dest;
3155 *p = value ? *(gint64*)value : 0;
3158 case MONO_TYPE_R4: {
3159 float *p = (float*)dest;
3160 *p = value ? *(float*)value : 0;
3163 case MONO_TYPE_R8: {
3164 double *p = (double*)dest;
3165 *p = value ? *(double*)value : 0;
3168 case MONO_TYPE_STRING:
3169 case MONO_TYPE_SZARRAY:
3170 case MONO_TYPE_CLASS:
3171 case MONO_TYPE_OBJECT:
3172 case MONO_TYPE_ARRAY:
3173 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3175 case MONO_TYPE_FNPTR:
3176 case MONO_TYPE_PTR: {
3177 gpointer *p = (gpointer*)dest;
3178 *p = deref_pointer? *(gpointer*)value: value;
3181 case MONO_TYPE_VALUETYPE:
3182 /* note that 't' and 'type->type' can be different */
3183 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3184 t = mono_class_enum_basetype (type->data.klass)->type;
3187 MonoClass *klass = mono_class_from_mono_type (type);
3188 int size = mono_class_value_size (klass, NULL);
3190 mono_gc_bzero_atomic (dest, size);
3192 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3195 case MONO_TYPE_GENERICINST:
3196 t = type->data.generic_class->container_class->byval_arg.type;
3199 g_error ("got type %x", type->type);
3204 * mono_field_set_value:
3205 * @obj: Instance object
3206 * @field: MonoClassField describing the field to set
3207 * @value: The value to be set
3209 * Sets the value of the field described by @field in the object instance @obj
3210 * to the value passed in @value. This method should only be used for instance
3211 * fields. For static fields, use mono_field_static_set_value.
3213 * The value must be on the native format of the field type.
3216 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3218 MONO_REQ_GC_UNSAFE_MODE;
3222 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3224 dest = (char*)obj + field->offset;
3225 mono_copy_value (field->type, dest, value, FALSE);
3229 * mono_field_static_set_value:
3230 * @field: MonoClassField describing the field to set
3231 * @value: The value to be set
3233 * Sets the value of the static field described by @field
3234 * to the value passed in @value.
3236 * The value must be on the native format of the field type.
3239 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3241 MONO_REQ_GC_UNSAFE_MODE;
3245 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3246 /* you cant set a constant! */
3247 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3249 if (field->offset == -1) {
3250 /* Special static */
3253 mono_domain_lock (vt->domain);
3254 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3255 mono_domain_unlock (vt->domain);
3256 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3258 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3260 mono_copy_value (field->type, dest, value, FALSE);
3264 * mono_vtable_get_static_field_data:
3266 * Internal use function: return a pointer to the memory holding the static fields
3267 * for a class or NULL if there are no static fields.
3268 * This is exported only for use by the debugger.
3271 mono_vtable_get_static_field_data (MonoVTable *vt)
3273 MONO_REQ_GC_NEUTRAL_MODE
3275 if (!vt->has_static_fields)
3277 return vt->vtable [vt->klass->vtable_size];
3281 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3283 MONO_REQ_GC_UNSAFE_MODE;
3287 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3288 if (field->offset == -1) {
3289 /* Special static */
3292 mono_domain_lock (vt->domain);
3293 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3294 mono_domain_unlock (vt->domain);
3295 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3297 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3300 src = (guint8*)obj + field->offset;
3307 * mono_field_get_value:
3308 * @obj: Object instance
3309 * @field: MonoClassField describing the field to fetch information from
3310 * @value: pointer to the location where the value will be stored
3312 * Use this routine to get the value of the field @field in the object
3315 * The pointer provided by value must be of the field type, for reference
3316 * types this is a MonoObject*, for value types its the actual pointer to
3321 * mono_field_get_value (obj, int_field, &i);
3324 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3326 MONO_REQ_GC_UNSAFE_MODE;
3332 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3334 src = (char*)obj + field->offset;
3335 mono_copy_value (field->type, value, src, TRUE);
3339 * mono_field_get_value_object:
3340 * @domain: domain where the object will be created (if boxing)
3341 * @field: MonoClassField describing the field to fetch information from
3342 * @obj: The object instance for the field.
3344 * Returns: a new MonoObject with the value from the given field. If the
3345 * field represents a value type, the value is boxed.
3349 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3351 MONO_REQ_GC_UNSAFE_MODE;
3356 MonoVTable *vtable = NULL;
3358 gboolean is_static = FALSE;
3359 gboolean is_ref = FALSE;
3360 gboolean is_literal = FALSE;
3361 gboolean is_ptr = FALSE;
3362 MonoType *type = mono_field_get_type_checked (field, &error);
3364 if (!mono_error_ok (&error))
3365 mono_error_raise_exception (&error); /* FIXME don't raise here */
3367 switch (type->type) {
3368 case MONO_TYPE_STRING:
3369 case MONO_TYPE_OBJECT:
3370 case MONO_TYPE_CLASS:
3371 case MONO_TYPE_ARRAY:
3372 case MONO_TYPE_SZARRAY:
3377 case MONO_TYPE_BOOLEAN:
3380 case MONO_TYPE_CHAR:
3389 case MONO_TYPE_VALUETYPE:
3390 is_ref = type->byref;
3392 case MONO_TYPE_GENERICINST:
3393 is_ref = !mono_type_generic_inst_is_valuetype (type);
3399 g_error ("type 0x%x not handled in "
3400 "mono_field_get_value_object", type->type);
3404 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3407 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3411 vtable = mono_class_vtable_full (domain, field->parent, &error);
3412 mono_error_raise_exception (&error); /* FIXME don't raise here */
3414 if (!vtable->initialized) {
3415 mono_runtime_class_init_full (vtable, &error);
3416 mono_error_raise_exception (&error); /* FIXME don't raise here */
3425 get_default_field_value (domain, field, &o);
3426 } else if (is_static) {
3427 mono_field_static_get_value (vtable, field, &o);
3429 mono_field_get_value (obj, field, &o);
3435 static MonoMethod *m;
3441 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3442 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3448 get_default_field_value (domain, field, v);
3449 } else if (is_static) {
3450 mono_field_static_get_value (vtable, field, v);
3452 mono_field_get_value (obj, field, v);
3455 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3456 args [0] = ptr ? *ptr : NULL;
3457 args [1] = mono_type_get_object_checked (mono_domain_get (), type, &error);
3458 mono_error_raise_exception (&error); /* FIXME don't raise here */
3460 o = mono_runtime_invoke_checked (m, NULL, args, &error);
3461 mono_error_raise_exception (&error); /* FIXME don't raise here */
3466 /* boxed value type */
3467 klass = mono_class_from_mono_type (type);
3469 if (mono_class_is_nullable (klass))
3470 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3472 o = mono_object_new_checked (domain, klass, &error);
3473 mono_error_raise_exception (&error); /* FIXME don't raise here */
3474 v = ((gchar *) o) + sizeof (MonoObject);
3477 get_default_field_value (domain, field, v);
3478 } else if (is_static) {
3479 mono_field_static_get_value (vtable, field, v);
3481 mono_field_get_value (obj, field, v);
3488 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3490 MONO_REQ_GC_UNSAFE_MODE;
3493 const char *p = blob;
3494 mono_metadata_decode_blob_size (p, &p);
3497 case MONO_TYPE_BOOLEAN:
3500 *(guint8 *) value = *p;
3502 case MONO_TYPE_CHAR:
3505 *(guint16*) value = read16 (p);
3509 *(guint32*) value = read32 (p);
3513 *(guint64*) value = read64 (p);
3516 readr4 (p, (float*) value);
3519 readr8 (p, (double*) value);
3521 case MONO_TYPE_STRING:
3522 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3524 case MONO_TYPE_CLASS:
3525 *(gpointer*) value = NULL;
3529 g_warning ("type 0x%02x should not be in constant table", type);
3535 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3537 MONO_REQ_GC_NEUTRAL_MODE;
3539 MonoTypeEnum def_type;
3542 data = mono_class_get_field_default_value (field, &def_type);
3543 mono_get_constant_value_from_blob (domain, def_type, data, value);
3547 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3549 MONO_REQ_GC_UNSAFE_MODE;
3553 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3555 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3556 get_default_field_value (vt->domain, field, value);
3560 if (field->offset == -1) {
3561 /* Special static */
3562 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3563 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3565 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3567 mono_copy_value (field->type, value, src, TRUE);
3571 * mono_field_static_get_value:
3572 * @vt: vtable to the object
3573 * @field: MonoClassField describing the field to fetch information from
3574 * @value: where the value is returned
3576 * Use this routine to get the value of the static field @field value.
3578 * The pointer provided by value must be of the field type, for reference
3579 * types this is a MonoObject*, for value types its the actual pointer to
3584 * mono_field_static_get_value (vt, int_field, &i);
3587 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3589 MONO_REQ_GC_NEUTRAL_MODE;
3591 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3595 * mono_property_set_value:
3596 * @prop: MonoProperty to set
3597 * @obj: instance object on which to act
3598 * @params: parameters to pass to the propery
3599 * @exc: optional exception
3601 * Invokes the property's set method with the given arguments on the
3602 * object instance obj (or NULL for static properties).
3604 * You can pass NULL as the exc argument if you don't want to
3605 * catch exceptions, otherwise, *exc will be set to the exception
3606 * thrown, if any. if an exception is thrown, you can't use the
3607 * MonoObject* result from the function.
3610 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3612 MONO_REQ_GC_UNSAFE_MODE;
3615 do_runtime_invoke (prop->set, obj, params, exc, &error);
3616 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3617 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3619 mono_error_raise_exception (&error); /* FIXME don't raise here */
3624 * mono_property_get_value:
3625 * @prop: MonoProperty to fetch
3626 * @obj: instance object on which to act
3627 * @params: parameters to pass to the propery
3628 * @exc: optional exception
3630 * Invokes the property's get method with the given arguments on the
3631 * object instance obj (or NULL for static properties).
3633 * You can pass NULL as the exc argument if you don't want to
3634 * catch exceptions, otherwise, *exc will be set to the exception
3635 * thrown, if any. if an exception is thrown, you can't use the
3636 * MonoObject* result from the function.
3638 * Returns: the value from invoking the get method on the property.
3641 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3643 MONO_REQ_GC_UNSAFE_MODE;
3646 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3647 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3648 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3650 mono_error_raise_exception (&error); /* FIXME don't raise here */
3657 * mono_nullable_init:
3658 * @buf: The nullable structure to initialize.
3659 * @value: the value to initialize from
3660 * @klass: the type for the object
3662 * Initialize the nullable structure pointed to by @buf from @value which
3663 * should be a boxed value type. The size of @buf should be able to hold
3664 * as much data as the @klass->instance_size (which is the number of bytes
3665 * that will be copies).
3667 * Since Nullables have variable structure, we can not define a C
3668 * structure for them.
3671 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3673 MONO_REQ_GC_UNSAFE_MODE;
3675 MonoClass *param_class = klass->cast_class;
3677 mono_class_setup_fields_locking (klass);
3678 g_assert (klass->fields_inited);
3680 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3681 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3683 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3685 if (param_class->has_references)
3686 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3688 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3690 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3695 * mono_nullable_box:
3696 * @buf: The buffer representing the data to be boxed
3697 * @klass: the type to box it as.
3699 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3703 mono_nullable_box (guint8 *buf, MonoClass *klass)
3705 MONO_REQ_GC_UNSAFE_MODE;
3709 MonoClass *param_class = klass->cast_class;
3711 mono_class_setup_fields_locking (klass);
3712 g_assert (klass->fields_inited);
3714 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3715 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3717 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3718 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, &error);
3719 mono_error_raise_exception (&error); /* FIXME don't raise here */
3720 if (param_class->has_references)
3721 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3723 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3731 * mono_get_delegate_invoke:
3732 * @klass: The delegate class
3734 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3737 mono_get_delegate_invoke (MonoClass *klass)
3739 MONO_REQ_GC_NEUTRAL_MODE;
3743 /* This is called at runtime, so avoid the slower search in metadata */
3744 mono_class_setup_methods (klass);
3745 if (mono_class_has_failure (klass))
3747 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3752 * mono_get_delegate_begin_invoke:
3753 * @klass: The delegate class
3755 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3758 mono_get_delegate_begin_invoke (MonoClass *klass)
3760 MONO_REQ_GC_NEUTRAL_MODE;
3764 /* This is called at runtime, so avoid the slower search in metadata */
3765 mono_class_setup_methods (klass);
3766 if (mono_class_has_failure (klass))
3768 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3773 * mono_get_delegate_end_invoke:
3774 * @klass: The delegate class
3776 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3779 mono_get_delegate_end_invoke (MonoClass *klass)
3781 MONO_REQ_GC_NEUTRAL_MODE;
3785 /* This is called at runtime, so avoid the slower search in metadata */
3786 mono_class_setup_methods (klass);
3787 if (mono_class_has_failure (klass))
3789 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3794 * mono_runtime_delegate_invoke:
3795 * @delegate: pointer to a delegate object.
3796 * @params: parameters for the delegate.
3797 * @exc: Pointer to the exception result.
3799 * Invokes the delegate method @delegate with the parameters provided.
3801 * You can pass NULL as the exc argument if you don't want to
3802 * catch exceptions, otherwise, *exc will be set to the exception
3803 * thrown, if any. if an exception is thrown, you can't use the
3804 * MonoObject* result from the function.
3807 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3809 MONO_REQ_GC_UNSAFE_MODE;
3813 MonoClass *klass = delegate->vtable->klass;
3816 im = mono_get_delegate_invoke (klass);
3818 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3821 o = mono_runtime_try_invoke (im, delegate, params, exc, &error);
3822 if (*exc == NULL && !mono_error_ok (&error))
3823 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3825 mono_error_cleanup (&error);
3827 o = mono_runtime_invoke_checked (im, delegate, params, &error);
3828 mono_error_raise_exception (&error); /* FIXME don't raise here */
3834 static char **main_args = NULL;
3835 static int num_main_args = 0;
3838 * mono_runtime_get_main_args:
3840 * Returns: a MonoArray with the arguments passed to the main program
3843 mono_runtime_get_main_args (void)
3845 MONO_REQ_GC_UNSAFE_MODE;
3849 MonoDomain *domain = mono_domain_get ();
3851 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3853 for (i = 0; i < num_main_args; ++i)
3854 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3860 free_main_args (void)
3862 MONO_REQ_GC_NEUTRAL_MODE;
3866 for (i = 0; i < num_main_args; ++i)
3867 g_free (main_args [i]);
3874 * mono_runtime_set_main_args:
3875 * @argc: number of arguments from the command line
3876 * @argv: array of strings from the command line
3878 * Set the command line arguments from an embedding application that doesn't otherwise call
3879 * mono_runtime_run_main ().
3882 mono_runtime_set_main_args (int argc, char* argv[])
3884 MONO_REQ_GC_NEUTRAL_MODE;
3889 main_args = g_new0 (char*, argc);
3890 num_main_args = argc;
3892 for (i = 0; i < argc; ++i) {
3895 utf8_arg = mono_utf8_from_external (argv[i]);
3896 if (utf8_arg == NULL) {
3897 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3898 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3902 main_args [i] = utf8_arg;
3909 * mono_runtime_run_main:
3910 * @method: the method to start the application with (usually Main)
3911 * @argc: number of arguments from the command line
3912 * @argv: array of strings from the command line
3913 * @exc: excetption results
3915 * Execute a standard Main() method (argc/argv contains the
3916 * executable name). This method also sets the command line argument value
3917 * needed by System.Environment.
3922 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3925 MONO_REQ_GC_UNSAFE_MODE;
3928 MonoArray *args = NULL;
3929 MonoDomain *domain = mono_domain_get ();
3930 gchar *utf8_fullpath;
3931 MonoMethodSignature *sig;
3933 g_assert (method != NULL);
3935 mono_thread_set_main (mono_thread_current ());
3937 main_args = g_new0 (char*, argc);
3938 num_main_args = argc;
3940 if (!g_path_is_absolute (argv [0])) {
3941 gchar *basename = g_path_get_basename (argv [0]);
3942 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3946 utf8_fullpath = mono_utf8_from_external (fullpath);
3947 if(utf8_fullpath == NULL) {
3948 /* Printing the arg text will cause glib to
3949 * whinge about "Invalid UTF-8", but at least
3950 * its relevant, and shows the problem text
3953 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3954 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3961 utf8_fullpath = mono_utf8_from_external (argv[0]);
3962 if(utf8_fullpath == NULL) {
3963 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3964 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3969 main_args [0] = utf8_fullpath;
3971 for (i = 1; i < argc; ++i) {
3974 utf8_arg=mono_utf8_from_external (argv[i]);
3975 if(utf8_arg==NULL) {
3976 /* Ditto the comment about Invalid UTF-8 here */
3977 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3978 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3982 main_args [i] = utf8_arg;
3987 sig = mono_method_signature (method);
3989 g_print ("Unable to load Main method.\n");
3993 if (sig->param_count) {
3994 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3995 for (i = 0; i < argc; ++i) {
3996 /* The encodings should all work, given that
3997 * we've checked all these args for the
4000 gchar *str = mono_utf8_from_external (argv [i]);
4001 MonoString *arg = mono_string_new (domain, str);
4002 mono_array_setref (args, i, arg);
4006 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
4009 mono_assembly_set_main (method->klass->image->assembly);
4011 return mono_runtime_exec_main (method, args, exc);
4015 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4017 static MonoMethod *serialize_method;
4023 if (!serialize_method) {
4024 MonoClass *klass = mono_class_get_remoting_services_class ();
4025 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4028 if (!serialize_method) {
4033 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4038 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4039 if (*exc == NULL && !mono_error_ok (&error))
4040 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4042 mono_error_cleanup (&error);
4051 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4053 MONO_REQ_GC_UNSAFE_MODE;
4055 static MonoMethod *deserialize_method;
4061 if (!deserialize_method) {
4062 MonoClass *klass = mono_class_get_remoting_services_class ();
4063 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4065 if (!deserialize_method) {
4073 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4074 if (*exc == NULL && !mono_error_ok (&error))
4075 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4077 mono_error_cleanup (&error);
4085 #ifndef DISABLE_REMOTING
4087 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
4089 MONO_REQ_GC_UNSAFE_MODE;
4091 static MonoMethod *get_proxy_method;
4094 MonoDomain *domain = mono_domain_get ();
4095 MonoRealProxy *real_proxy;
4096 MonoReflectionType *reflection_type;
4097 MonoTransparentProxy *transparent_proxy;
4099 if (!get_proxy_method)
4100 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4102 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4104 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, &error);
4105 mono_error_raise_exception (&error); /* FIXME don't raise here */
4106 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, &error);
4107 mono_error_raise_exception (&error); /* FIXME don't raise here */
4109 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4110 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4114 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, exc, &error);
4115 if (*exc == NULL && !mono_error_ok (&error))
4116 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME change make_transparent_proxy outarg to MonoError */
4118 mono_error_cleanup (&error);
4122 return (MonoObject*) transparent_proxy;
4124 #endif /* DISABLE_REMOTING */
4127 * mono_object_xdomain_representation
4129 * @target_domain: a domain
4130 * @exc: pointer to a MonoObject*
4132 * Creates a representation of obj in the domain target_domain. This
4133 * is either a copy of obj arrived through via serialization and
4134 * deserialization or a proxy, depending on whether the object is
4135 * serializable or marshal by ref. obj must not be in target_domain.
4137 * If the object cannot be represented in target_domain, NULL is
4138 * returned and *exc is set to an appropriate exception.
4141 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
4143 MONO_REQ_GC_UNSAFE_MODE;
4145 MonoObject *deserialized = NULL;
4146 gboolean failure = FALSE;
4148 g_assert (exc != NULL);
4151 #ifndef DISABLE_REMOTING
4152 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4153 deserialized = make_transparent_proxy (obj, &failure, exc);
4158 MonoDomain *domain = mono_domain_get ();
4159 MonoObject *serialized;
4161 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4162 serialized = serialize_object (obj, &failure, exc);
4163 mono_domain_set_internal_with_options (target_domain, FALSE);
4165 deserialized = deserialize_object (serialized, &failure, exc);
4166 if (domain != target_domain)
4167 mono_domain_set_internal_with_options (domain, FALSE);
4170 return deserialized;
4173 /* Used in call_unhandled_exception_delegate */
4175 create_unhandled_exception_eventargs (MonoObject *exc)
4177 MONO_REQ_GC_UNSAFE_MODE;
4182 MonoMethod *method = NULL;
4183 MonoBoolean is_terminating = TRUE;
4186 klass = mono_class_get_unhandled_exception_event_args_class ();
4187 mono_class_init (klass);
4189 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4190 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4194 args [1] = &is_terminating;
4196 obj = mono_object_new_checked (mono_domain_get (), klass, &error);
4197 mono_error_raise_exception (&error); /* FIXME don't raise here */
4199 mono_runtime_invoke_checked (method, obj, args, &error);
4200 mono_error_raise_exception (&error); /* FIXME don't raise here */
4205 /* Used in mono_unhandled_exception */
4207 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4208 MONO_REQ_GC_UNSAFE_MODE;
4210 MonoObject *e = NULL;
4212 MonoDomain *current_domain = mono_domain_get ();
4214 if (domain != current_domain)
4215 mono_domain_set_internal_with_options (domain, FALSE);
4217 g_assert (domain == mono_object_domain (domain->domain));
4219 if (mono_object_domain (exc) != domain) {
4220 MonoObject *serialization_exc;
4222 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
4224 if (serialization_exc) {
4226 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
4229 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4230 "System.Runtime.Serialization", "SerializationException",
4231 "Could not serialize unhandled exception.");
4235 g_assert (mono_object_domain (exc) == domain);
4237 pa [0] = domain->domain;
4238 pa [1] = create_unhandled_exception_eventargs (exc);
4239 mono_runtime_delegate_invoke (delegate, pa, &e);
4241 if (domain != current_domain)
4242 mono_domain_set_internal_with_options (current_domain, FALSE);
4246 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4247 if (!mono_error_ok (&error)) {
4248 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4249 mono_error_cleanup (&error);
4251 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4257 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4260 * mono_runtime_unhandled_exception_policy_set:
4261 * @policy: the new policy
4263 * This is a VM internal routine.
4265 * Sets the runtime policy for handling unhandled exceptions.
4268 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4269 runtime_unhandled_exception_policy = policy;
4273 * mono_runtime_unhandled_exception_policy_get:
4275 * This is a VM internal routine.
4277 * Gets the runtime policy for handling unhandled exceptions.
4279 MonoRuntimeUnhandledExceptionPolicy
4280 mono_runtime_unhandled_exception_policy_get (void) {
4281 return runtime_unhandled_exception_policy;
4285 * mono_unhandled_exception:
4286 * @exc: exception thrown
4288 * This is a VM internal routine.
4290 * We call this function when we detect an unhandled exception
4291 * in the default domain.
4293 * It invokes the * UnhandledException event in AppDomain or prints
4294 * a warning to the console
4297 mono_unhandled_exception (MonoObject *exc)
4299 MONO_REQ_GC_UNSAFE_MODE;
4301 MonoClassField *field;
4302 MonoDomain *current_domain, *root_domain;
4303 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4305 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4308 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4311 current_domain = mono_domain_get ();
4312 root_domain = mono_get_root_domain ();
4314 root_appdomain_delegate = mono_field_get_value_object (root_domain, field, (MonoObject*) root_domain->domain);
4315 if (current_domain != root_domain)
4316 current_appdomain_delegate = mono_field_get_value_object (current_domain, field, (MonoObject*) current_domain->domain);
4318 /* set exitcode only if we will abort the process */
4319 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4320 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4321 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4323 mono_environment_exitcode_set (1);
4326 mono_print_unhandled_exception (exc);
4328 if (root_appdomain_delegate)
4329 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4330 if (current_appdomain_delegate)
4331 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4336 * mono_runtime_exec_managed_code:
4337 * @domain: Application domain
4338 * @main_func: function to invoke from the execution thread
4339 * @main_args: parameter to the main_func
4341 * Launch a new thread to execute a function
4343 * main_func is called back from the thread with main_args as the
4344 * parameter. The callback function is expected to start Main()
4345 * eventually. This function then waits for all managed threads to
4347 * It is not necesseray anymore to execute managed code in a subthread,
4348 * so this function should not be used anymore by default: just
4349 * execute the code and then call mono_thread_manage ().
4352 mono_runtime_exec_managed_code (MonoDomain *domain,
4353 MonoMainThreadFunc main_func,
4356 mono_thread_create (domain, main_func, main_args);
4358 mono_thread_manage ();
4362 * Execute a standard Main() method (args doesn't contain the
4366 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4368 MONO_REQ_GC_UNSAFE_MODE;
4374 MonoCustomAttrInfo* cinfo;
4375 gboolean has_stathread_attribute;
4376 MonoInternalThread* thread = mono_thread_internal_current ();
4382 domain = mono_object_domain (args);
4383 if (!domain->entry_assembly) {
4385 MonoAssembly *assembly;
4387 assembly = method->klass->image->assembly;
4388 domain->entry_assembly = assembly;
4389 /* Domains created from another domain already have application_base and configuration_file set */
4390 if (domain->setup->application_base == NULL) {
4391 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4394 if (domain->setup->configuration_file == NULL) {
4395 str = g_strconcat (assembly->image->name, ".config", NULL);
4396 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4398 mono_domain_set_options_from_config (domain);
4402 cinfo = mono_custom_attrs_from_method_checked (method, &error);
4403 mono_error_cleanup (&error); /* FIXME warn here? */
4405 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4407 mono_custom_attrs_free (cinfo);
4409 has_stathread_attribute = FALSE;
4411 if (has_stathread_attribute) {
4412 thread->apartment_state = ThreadApartmentState_STA;
4414 thread->apartment_state = ThreadApartmentState_MTA;
4416 mono_thread_init_apartment_state ();
4418 /* FIXME: check signature of method */
4419 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4422 res = mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4423 if (*exc == NULL && !mono_error_ok (&error))
4424 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4426 mono_error_cleanup (&error);
4428 res = mono_runtime_invoke_checked (method, NULL, pa, &error);
4429 mono_error_raise_exception (&error); /* FIXME don't raise here */
4433 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4437 mono_environment_exitcode_set (rval);
4440 mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4441 if (*exc == NULL && !mono_error_ok (&error))
4442 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4444 mono_error_cleanup (&error);
4446 mono_runtime_invoke_checked (method, NULL, pa, &error);
4447 mono_error_raise_exception (&error); /* FIXME don't raise here */
4453 /* If the return type of Main is void, only
4454 * set the exitcode if an exception was thrown
4455 * (we don't want to blow away an
4456 * explicitly-set exit code)
4459 mono_environment_exitcode_set (rval);
4467 * mono_runtime_invoke_array:
4468 * @method: method to invoke
4469 * @obJ: object instance
4470 * @params: arguments to the method
4471 * @exc: exception information.
4473 * Invokes the method represented by @method on the object @obj.
4475 * obj is the 'this' pointer, it should be NULL for static
4476 * methods, a MonoObject* for object instances and a pointer to
4477 * the value type for value types.
4479 * The params array contains the arguments to the method with the
4480 * same convention: MonoObject* pointers for object instances and
4481 * pointers to the value type otherwise. The _invoke_array
4482 * variant takes a C# object[] as the params argument (MonoArray
4483 * *params): in this case the value types are boxed inside the
4484 * respective reference representation.
4486 * From unmanaged code you'll usually use the
4487 * mono_runtime_invoke_checked() variant.
4489 * Note that this function doesn't handle virtual methods for
4490 * you, it will exec the exact method you pass: we still need to
4491 * expose a function to lookup the derived class implementation
4492 * of a virtual method (there are examples of this in the code,
4495 * You can pass NULL as the exc argument if you don't want to
4496 * catch exceptions, otherwise, *exc will be set to the exception
4497 * thrown, if any. if an exception is thrown, you can't use the
4498 * MonoObject* result from the function.
4500 * If the method returns a value type, it is boxed in an object
4504 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4507 MONO_REQ_GC_UNSAFE_MODE;
4510 MonoMethodSignature *sig = mono_method_signature (method);
4511 gpointer *pa = NULL;
4514 gboolean has_byref_nullables = FALSE;
4516 if (NULL != params) {
4517 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4518 for (i = 0; i < mono_array_length (params); i++) {
4519 MonoType *t = sig->params [i];
4525 case MONO_TYPE_BOOLEAN:
4528 case MONO_TYPE_CHAR:
4537 case MONO_TYPE_VALUETYPE:
4538 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4539 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4540 pa [i] = mono_array_get (params, MonoObject*, i);
4542 has_byref_nullables = TRUE;
4544 /* MS seems to create the objects if a null is passed in */
4545 if (!mono_array_get (params, MonoObject*, i)) {
4546 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (sig->params [i]), &error);
4547 mono_error_raise_exception (&error); /* FIXME don't raise here */
4548 mono_array_setref (params, i, o);
4553 * We can't pass the unboxed vtype byref to the callee, since
4554 * that would mean the callee would be able to modify boxed
4555 * primitive types. So we (and MS) make a copy of the boxed
4556 * object, pass that to the callee, and replace the original
4557 * boxed object in the arg array with the copy.
4559 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4560 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4561 mono_array_setref (params, i, copy);
4564 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4567 case MONO_TYPE_STRING:
4568 case MONO_TYPE_OBJECT:
4569 case MONO_TYPE_CLASS:
4570 case MONO_TYPE_ARRAY:
4571 case MONO_TYPE_SZARRAY:
4573 pa [i] = mono_array_addr (params, MonoObject*, i);
4574 // FIXME: I need to check this code path
4576 pa [i] = mono_array_get (params, MonoObject*, i);
4578 case MONO_TYPE_GENERICINST:
4580 t = &t->data.generic_class->container_class->this_arg;
4582 t = &t->data.generic_class->container_class->byval_arg;
4584 case MONO_TYPE_PTR: {
4587 /* The argument should be an IntPtr */
4588 arg = mono_array_get (params, MonoObject*, i);
4592 g_assert (arg->vtable->klass == mono_defaults.int_class);
4593 pa [i] = ((MonoIntPtr*)arg)->m_value;
4598 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4603 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4606 if (mono_class_is_nullable (method->klass)) {
4607 /* Need to create a boxed vtype instead */
4613 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4617 obj = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4618 g_assert (obj && mono_error_ok (&error)); /*maybe we should raise a TLE instead?*/ /* FIXME don't swallow error */
4619 #ifndef DISABLE_REMOTING
4620 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4621 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4624 if (method->klass->valuetype)
4625 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
4628 } else if (method->klass->valuetype) {
4629 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4633 mono_runtime_try_invoke (method, o, pa, exc, &error);
4634 if (*exc == NULL && !mono_error_ok (&error))
4635 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4637 mono_error_cleanup (&error);
4639 mono_runtime_invoke_checked (method, o, pa, &error);
4640 mono_error_raise_exception (&error); /* FIXME don't raise here */
4643 return (MonoObject *)obj;
4645 if (mono_class_is_nullable (method->klass)) {
4646 MonoObject *nullable;
4648 /* Convert the unboxed vtype into a Nullable structure */
4649 nullable = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4650 mono_error_raise_exception (&error); /* FIXME don't raise here */
4652 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4653 obj = mono_object_unbox (nullable);
4656 /* obj must be already unboxed if needed */
4658 res = mono_runtime_try_invoke (method, obj, pa, exc, &error);
4659 if (*exc == NULL && !mono_error_ok (&error))
4660 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4662 mono_error_cleanup (&error);
4664 res = mono_runtime_invoke_checked (method, obj, pa, &error);
4665 mono_error_raise_exception (&error); /* FIXME don't raise here */
4668 if (sig->ret->type == MONO_TYPE_PTR) {
4669 MonoClass *pointer_class;
4670 static MonoMethod *box_method;
4672 MonoObject *box_exc;
4675 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4676 * convert it to a Pointer object.
4678 pointer_class = mono_class_get_pointer_class ();
4680 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4682 g_assert (res->vtable->klass == mono_defaults.int_class);
4683 box_args [0] = ((MonoIntPtr*)res)->m_value;
4684 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, &error);
4685 mono_error_raise_exception (&error); /* FIXME don't raise here */
4687 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, &error);
4688 g_assert (box_exc == NULL);
4689 mono_error_assert_ok (&error);
4692 if (has_byref_nullables) {
4694 * The runtime invoke wrapper already converted byref nullables back,
4695 * and stored them in pa, we just need to copy them back to the
4698 for (i = 0; i < mono_array_length (params); i++) {
4699 MonoType *t = sig->params [i];
4701 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4702 mono_array_setref (params, i, pa [i]);
4712 * @klass: the class of the object that we want to create
4714 * Returns: a newly created object whose definition is
4715 * looked up using @klass. This will not invoke any constructors,
4716 * so the consumer of this routine has to invoke any constructors on
4717 * its own to initialize the object.
4719 * It returns NULL on failure.
4722 mono_object_new (MonoDomain *domain, MonoClass *klass)
4724 MONO_REQ_GC_UNSAFE_MODE;
4728 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4730 mono_error_raise_exception (&error);
4735 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
4737 MONO_REQ_GC_UNSAFE_MODE;
4741 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4743 mono_error_raise_exception (&error);
4748 * mono_object_new_checked:
4749 * @klass: the class of the object that we want to create
4750 * @error: set on error
4752 * Returns: a newly created object whose definition is
4753 * looked up using @klass. This will not invoke any constructors,
4754 * so the consumer of this routine has to invoke any constructors on
4755 * its own to initialize the object.
4757 * It returns NULL on failure and sets @error.
4760 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
4762 MONO_REQ_GC_UNSAFE_MODE;
4766 vtable = mono_class_vtable (domain, klass);
4767 g_assert (vtable); /* FIXME don't swallow the error */
4769 MonoObject *o = mono_object_new_specific_checked (vtable, error);
4774 * mono_object_new_pinned:
4776 * Same as mono_object_new, but the returned object will be pinned.
4777 * For SGEN, these objects will only be freed at appdomain unload.
4780 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
4782 MONO_REQ_GC_UNSAFE_MODE;
4786 mono_error_init (error);
4788 vtable = mono_class_vtable (domain, klass);
4789 g_assert (vtable); /* FIXME don't swallow the error */
4791 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4793 if (G_UNLIKELY (!o))
4794 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
4795 else if (G_UNLIKELY (vtable->klass->has_finalize))
4796 mono_object_register_finalizer (o, error);
4802 * mono_object_new_specific:
4803 * @vtable: the vtable of the object that we want to create
4805 * Returns: A newly created object with class and domain specified
4809 mono_object_new_specific (MonoVTable *vtable)
4812 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4813 mono_error_raise_exception (&error);
4819 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
4821 MONO_REQ_GC_UNSAFE_MODE;
4825 mono_error_init (error);
4827 /* check for is_com_object for COM Interop */
4828 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4831 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4834 MonoClass *klass = mono_class_get_activation_services_class ();
4837 mono_class_init (klass);
4839 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4841 mono_error_set_generic_error (error, "System", "NotSupportedException", "Linked away.");
4844 vtable->domain->create_proxy_for_type_method = im;
4847 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
4848 if (!mono_error_ok (error))
4851 o = mono_runtime_invoke_checked (im, NULL, pa, error);
4852 if (!mono_error_ok (error))
4859 return mono_object_new_alloc_specific_checked (vtable, error);
4863 ves_icall_object_new_specific (MonoVTable *vtable)
4866 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4867 mono_error_raise_exception (&error);
4873 * mono_object_new_alloc_specific:
4874 * @vtable: virtual table for the object.
4876 * This function allocates a new `MonoObject` with the type derived
4877 * from the @vtable information. If the class of this object has a
4878 * finalizer, then the object will be tracked for finalization.
4880 * This method might raise an exception on errors. Use the
4881 * `mono_object_new_fast_checked` method if you want to manually raise
4884 * Returns: the allocated object.
4887 mono_object_new_alloc_specific (MonoVTable *vtable)
4890 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
4891 mono_error_raise_exception (&error);
4897 * mono_object_new_alloc_specific_checked:
4898 * @vtable: virtual table for the object.
4899 * @error: holds the error return value.
4901 * This function allocates a new `MonoObject` with the type derived
4902 * from the @vtable information. If the class of this object has a
4903 * finalizer, then the object will be tracked for finalization.
4905 * If there is not enough memory, the @error parameter will be set
4906 * and will contain a user-visible message with the amount of bytes
4907 * that were requested.
4909 * Returns: the allocated object, or NULL if there is not enough memory
4913 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
4915 MONO_REQ_GC_UNSAFE_MODE;
4919 mono_error_init (error);
4921 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4923 if (G_UNLIKELY (!o))
4924 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4925 else if (G_UNLIKELY (vtable->klass->has_finalize))
4926 mono_object_register_finalizer (o, error);
4932 * mono_object_new_fast:
4933 * @vtable: virtual table for the object.
4935 * This function allocates a new `MonoObject` with the type derived
4936 * from the @vtable information. The returned object is not tracked
4937 * for finalization. If your object implements a finalizer, you should
4938 * use `mono_object_new_alloc_specific` instead.
4940 * This method might raise an exception on errors. Use the
4941 * `mono_object_new_fast_checked` method if you want to manually raise
4944 * Returns: the allocated object.
4947 mono_object_new_fast (MonoVTable *vtable)
4950 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4951 mono_error_raise_exception (&error);
4957 * mono_object_new_fast_checked:
4958 * @vtable: virtual table for the object.
4959 * @error: holds the error return value.
4961 * This function allocates a new `MonoObject` with the type derived
4962 * from the @vtable information. The returned object is not tracked
4963 * for finalization. If your object implements a finalizer, you should
4964 * use `mono_object_new_alloc_specific_checked` instead.
4966 * If there is not enough memory, the @error parameter will be set
4967 * and will contain a user-visible message with the amount of bytes
4968 * that were requested.
4970 * Returns: the allocated object, or NULL if there is not enough memory
4974 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
4976 MONO_REQ_GC_UNSAFE_MODE;
4980 mono_error_init (error);
4982 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4984 if (G_UNLIKELY (!o))
4985 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4991 ves_icall_object_new_fast (MonoVTable *vtable)
4994 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4995 mono_error_raise_exception (&error);
5001 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5003 MONO_REQ_GC_UNSAFE_MODE;
5007 mono_error_init (error);
5009 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5011 if (G_UNLIKELY (!o))
5012 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5013 else if (G_UNLIKELY (vtable->klass->has_finalize))
5014 mono_object_register_finalizer (o, error);
5020 * mono_class_get_allocation_ftn:
5022 * @for_box: the object will be used for boxing
5023 * @pass_size_in_words:
5025 * Return the allocation function appropriate for the given class.
5029 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5031 MONO_REQ_GC_NEUTRAL_MODE;
5033 *pass_size_in_words = FALSE;
5035 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
5036 return ves_icall_object_new_specific;
5038 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5040 return ves_icall_object_new_fast;
5043 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5044 * of the overhead of parameter passing.
5047 *pass_size_in_words = TRUE;
5048 #ifdef GC_REDIRECT_TO_LOCAL
5049 return GC_local_gcj_fast_malloc;
5051 return GC_gcj_fast_malloc;
5056 return ves_icall_object_new_specific;
5060 * mono_object_new_from_token:
5061 * @image: Context where the type_token is hosted
5062 * @token: a token of the type that we want to create
5064 * Returns: A newly created object whose definition is
5065 * looked up using @token in the @image image
5068 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5070 MONO_REQ_GC_UNSAFE_MODE;
5076 klass = mono_class_get_checked (image, token, &error);
5077 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
5079 result = mono_object_new_checked (domain, klass, &error);
5081 mono_error_raise_exception (&error); /* FIXME don't raise here */
5088 * mono_object_clone:
5089 * @obj: the object to clone
5091 * Returns: A newly created object who is a shallow copy of @obj
5094 mono_object_clone (MonoObject *obj)
5097 MonoObject *o = mono_object_clone_checked (obj, &error);
5098 mono_error_raise_exception (&error);
5104 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5106 MONO_REQ_GC_UNSAFE_MODE;
5111 mono_error_init (error);
5113 size = obj->vtable->klass->instance_size;
5115 if (obj->vtable->klass->rank)
5116 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
5118 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5120 if (G_UNLIKELY (!o)) {
5121 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5125 /* If the object doesn't contain references this will do a simple memmove. */
5126 mono_gc_wbarrier_object_copy (o, obj);
5128 if (obj->vtable->klass->has_finalize)
5129 mono_object_register_finalizer (o, error);
5134 * mono_array_full_copy:
5135 * @src: source array to copy
5136 * @dest: destination array
5138 * Copies the content of one array to another with exactly the same type and size.
5141 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5143 MONO_REQ_GC_UNSAFE_MODE;
5146 MonoClass *klass = src->obj.vtable->klass;
5148 g_assert (klass == dest->obj.vtable->klass);
5150 size = mono_array_length (src);
5151 g_assert (size == mono_array_length (dest));
5152 size *= mono_array_element_size (klass);
5154 if (klass->element_class->valuetype) {
5155 if (klass->element_class->has_references)
5156 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5158 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5160 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5163 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5168 * mono_array_clone_in_domain:
5169 * @domain: the domain in which the array will be cloned into
5170 * @array: the array to clone
5172 * This routine returns a copy of the array that is hosted on the
5173 * specified MonoDomain.
5176 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
5178 MONO_REQ_GC_UNSAFE_MODE;
5184 MonoClass *klass = array->obj.vtable->klass;
5186 if (array->bounds == NULL) {
5187 size = mono_array_length (array);
5188 o = mono_array_new_full_checked (domain, klass, &size, NULL, &error);
5189 mono_error_raise_exception (&error); /* FIXME don't raise here */
5191 size *= mono_array_element_size (klass);
5193 if (klass->element_class->valuetype) {
5194 if (klass->element_class->has_references)
5195 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5197 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5199 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5202 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5207 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5208 size = mono_array_element_size (klass);
5209 for (i = 0; i < klass->rank; ++i) {
5210 sizes [i] = array->bounds [i].length;
5211 size *= array->bounds [i].length;
5212 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5214 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, &error);
5215 mono_error_raise_exception (&error); /* FIXME don't raise here */
5217 if (klass->element_class->valuetype) {
5218 if (klass->element_class->has_references)
5219 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5221 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5223 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5226 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5234 * @array: the array to clone
5236 * Returns: A newly created array who is a shallow copy of @array
5239 mono_array_clone (MonoArray *array)
5241 MONO_REQ_GC_UNSAFE_MODE;
5243 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
5246 /* helper macros to check for overflow when calculating the size of arrays */
5247 #ifdef MONO_BIG_ARRAYS
5248 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5249 #define MYGUINT_MAX MYGUINT64_MAX
5250 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5251 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5252 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5253 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5254 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5256 #define MYGUINT32_MAX 4294967295U
5257 #define MYGUINT_MAX MYGUINT32_MAX
5258 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5259 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5260 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5261 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5262 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5266 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5268 MONO_REQ_GC_NEUTRAL_MODE;
5272 byte_len = mono_array_element_size (klass);
5273 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5276 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5278 byte_len += MONO_SIZEOF_MONO_ARRAY;
5286 * mono_array_new_full:
5287 * @domain: domain where the object is created
5288 * @array_class: array class
5289 * @lengths: lengths for each dimension in the array
5290 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5292 * This routine creates a new array objects with the given dimensions,
5293 * lower bounds and type.
5296 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5299 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5300 mono_error_raise_exception (&error);
5306 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5308 MONO_REQ_GC_UNSAFE_MODE;
5310 uintptr_t byte_len = 0, len, bounds_size;
5313 MonoArrayBounds *bounds;
5317 mono_error_init (error);
5319 if (!array_class->inited)
5320 mono_class_init (array_class);
5324 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5325 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5327 if (len > MONO_ARRAY_MAX_INDEX) {
5328 mono_error_set_generic_error (error, "System", "OverflowException", "");
5333 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5335 for (i = 0; i < array_class->rank; ++i) {
5336 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5337 mono_error_set_generic_error (error, "System", "OverflowException", "");
5340 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5341 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5348 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5349 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5355 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5356 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5359 byte_len = (byte_len + 3) & ~3;
5360 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5361 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5364 byte_len += bounds_size;
5367 * Following three lines almost taken from mono_object_new ():
5368 * they need to be kept in sync.
5370 vtable = mono_class_vtable_full (domain, array_class, error);
5371 return_val_if_nok (error, NULL);
5374 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5376 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5378 if (G_UNLIKELY (!o)) {
5379 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5383 array = (MonoArray*)o;
5385 bounds = array->bounds;
5388 for (i = 0; i < array_class->rank; ++i) {
5389 bounds [i].length = lengths [i];
5391 bounds [i].lower_bound = lower_bounds [i];
5400 * @domain: domain where the object is created
5401 * @eclass: element class
5402 * @n: number of array elements
5404 * This routine creates a new szarray with @n elements of type @eclass.
5407 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5409 MONO_REQ_GC_UNSAFE_MODE;
5415 ac = mono_array_class_get (eclass, 1);
5418 MonoVTable *vtable = mono_class_vtable_full (domain, ac, &error);
5419 mono_error_raise_exception (&error); /* FIXME don't raise here */
5421 arr = mono_array_new_specific_checked (vtable, n, &error);
5422 mono_error_raise_exception (&error); /* FIXME don't raise here */
5428 * mono_array_new_specific:
5429 * @vtable: a vtable in the appropriate domain for an initialized class
5430 * @n: number of array elements
5432 * This routine is a fast alternative to mono_array_new() for code which
5433 * can be sure about the domain it operates in.
5436 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5439 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5440 mono_error_raise_exception (&error); /* FIXME don't raise here */
5446 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5448 MONO_REQ_GC_UNSAFE_MODE;
5453 mono_error_init (error);
5455 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5456 mono_error_set_generic_error (error, "System", "OverflowException", "");
5460 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5461 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5464 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5466 if (G_UNLIKELY (!o)) {
5467 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5471 return (MonoArray*)o;
5475 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5478 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5479 mono_error_raise_exception (&error);
5485 * mono_string_new_utf16:
5486 * @text: a pointer to an utf16 string
5487 * @len: the length of the string
5489 * Returns: A newly created string object which contains @text.
5492 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5494 MONO_REQ_GC_UNSAFE_MODE;
5497 MonoString *res = NULL;
5498 res = mono_string_new_utf16_checked (domain, text, len, &error);
5499 mono_error_raise_exception (&error);
5505 * mono_string_new_utf16_checked:
5506 * @text: a pointer to an utf16 string
5507 * @len: the length of the string
5508 * @error: written on error.
5510 * Returns: A newly created string object which contains @text.
5511 * On error, returns NULL and sets @error.
5514 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5516 MONO_REQ_GC_UNSAFE_MODE;
5520 mono_error_init (error);
5522 s = mono_string_new_size_checked (domain, len, error);
5524 memcpy (mono_string_chars (s), text, len * 2);
5530 * mono_string_new_utf32:
5531 * @text: a pointer to an utf32 string
5532 * @len: the length of the string
5534 * Returns: A newly created string object which contains @text.
5537 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5539 MONO_REQ_GC_UNSAFE_MODE;
5543 mono_unichar2 *utf16_output = NULL;
5544 gint32 utf16_len = 0;
5545 GError *gerror = NULL;
5546 glong items_written;
5548 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
5551 g_error_free (gerror);
5553 while (utf16_output [utf16_len]) utf16_len++;
5555 s = mono_string_new_size_checked (domain, utf16_len, &error);
5556 mono_error_raise_exception (&error); /* FIXME don't raise here */
5558 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5560 g_free (utf16_output);
5566 * mono_string_new_size:
5567 * @text: a pointer to an utf16 string
5568 * @len: the length of the string
5570 * Returns: A newly created string object of @len
5573 mono_string_new_size (MonoDomain *domain, gint32 len)
5576 MonoString *str = mono_string_new_size_checked (domain, len, &error);
5577 mono_error_raise_exception (&error);
5583 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
5585 MONO_REQ_GC_UNSAFE_MODE;
5591 mono_error_init (error);
5593 /* check for overflow */
5594 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
5595 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
5599 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5600 g_assert (size > 0);
5602 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5605 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
5607 if (G_UNLIKELY (!s)) {
5608 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5616 * mono_string_new_len:
5617 * @text: a pointer to an utf8 string
5618 * @length: number of bytes in @text to consider
5620 * Returns: A newly created string object which contains @text.
5623 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5625 MONO_REQ_GC_UNSAFE_MODE;
5628 GError *eg_error = NULL;
5629 MonoString *o = NULL;
5631 glong items_written;
5633 mono_error_init (&error);
5635 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
5638 o = mono_string_new_utf16_checked (domain, ut, items_written, &error);
5640 g_error_free (eg_error);
5644 mono_error_raise_exception (&error); /* FIXME don't raise here */
5650 * @text: a pointer to an utf8 string
5652 * Returns: A newly created string object which contains @text.
5654 * This function asserts if it cannot allocate a new string.
5656 * @deprecated Use mono_string_new_checked in new code.
5659 mono_string_new (MonoDomain *domain, const char *text)
5662 MonoString *res = NULL;
5663 res = mono_string_new_checked (domain, text, &error);
5664 mono_error_assert_ok (&error);
5669 * mono_string_new_checked:
5670 * @text: a pointer to an utf8 string
5671 * @merror: set on error
5673 * Returns: A newly created string object which contains @text.
5674 * On error returns NULL and sets @merror.
5677 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
5679 MONO_REQ_GC_UNSAFE_MODE;
5681 GError *eg_error = NULL;
5682 MonoString *o = NULL;
5684 glong items_written;
5687 mono_error_init (error);
5691 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
5694 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
5696 g_error_free (eg_error);
5699 mono_error_raise_exception (error);
5701 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5706 MonoString *o = NULL;
5708 if (!g_utf8_validate (text, -1, &end)) {
5709 mono_error_set_argument (error, "text", "Not a valid utf8 string");
5713 len = g_utf8_strlen (text, -1);
5714 o = mono_string_new_size_checked (domain, len, error);
5717 str = mono_string_chars (o);
5719 while (text < end) {
5720 *str++ = g_utf8_get_char (text);
5721 text = g_utf8_next_char (text);
5730 * mono_string_new_wrapper:
5731 * @text: pointer to utf8 characters.
5733 * Helper function to create a string object from @text in the current domain.
5736 mono_string_new_wrapper (const char *text)
5738 MONO_REQ_GC_UNSAFE_MODE;
5740 MonoDomain *domain = mono_domain_get ();
5743 return mono_string_new (domain, text);
5750 * @class: the class of the value
5751 * @value: a pointer to the unboxed data
5753 * Returns: A newly created object which contains @value.
5756 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
5758 MONO_REQ_GC_UNSAFE_MODE;
5765 g_assert (klass->valuetype);
5766 if (mono_class_is_nullable (klass))
5767 return mono_nullable_box ((guint8 *)value, klass);
5769 vtable = mono_class_vtable (domain, klass);
5772 size = mono_class_instance_size (klass);
5773 res = mono_object_new_alloc_specific_checked (vtable, &error);
5774 mono_error_raise_exception (&error); /* FIXME don't raise here */
5776 size = size - sizeof (MonoObject);
5779 g_assert (size == mono_class_value_size (klass, NULL));
5780 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
5782 #if NO_UNALIGNED_ACCESS
5783 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5787 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5790 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5793 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5796 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5799 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5803 if (klass->has_finalize) {
5804 mono_object_register_finalizer (res, &error);
5805 mono_error_raise_exception (&error); /* FIXME don't raise here */
5812 * @dest: destination pointer
5813 * @src: source pointer
5814 * @klass: a valuetype class
5816 * Copy a valuetype from @src to @dest. This function must be used
5817 * when @klass contains references fields.
5820 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5822 MONO_REQ_GC_UNSAFE_MODE;
5824 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5828 * mono_value_copy_array:
5829 * @dest: destination array
5830 * @dest_idx: index in the @dest array
5831 * @src: source pointer
5832 * @count: number of items
5834 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5835 * This function must be used when @klass contains references fields.
5836 * Overlap is handled.
5839 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5841 MONO_REQ_GC_UNSAFE_MODE;
5843 int size = mono_array_element_size (dest->obj.vtable->klass);
5844 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5845 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5846 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5850 * mono_object_get_domain:
5851 * @obj: object to query
5853 * Returns: the MonoDomain where the object is hosted
5856 mono_object_get_domain (MonoObject *obj)
5858 MONO_REQ_GC_UNSAFE_MODE;
5860 return mono_object_domain (obj);
5864 * mono_object_get_class:
5865 * @obj: object to query
5867 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
5869 * Returns: the MonoClass of the object.
5872 mono_object_get_class (MonoObject *obj)
5874 MONO_REQ_GC_UNSAFE_MODE;
5876 return mono_object_class (obj);
5879 * mono_object_get_size:
5880 * @o: object to query
5882 * Returns: the size, in bytes, of @o
5885 mono_object_get_size (MonoObject* o)
5887 MONO_REQ_GC_UNSAFE_MODE;
5889 MonoClass* klass = mono_object_class (o);
5890 if (klass == mono_defaults.string_class) {
5891 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5892 } else if (o->vtable->rank) {
5893 MonoArray *array = (MonoArray*)o;
5894 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
5895 if (array->bounds) {
5898 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5902 return mono_class_instance_size (klass);
5907 * mono_object_unbox:
5908 * @obj: object to unbox
5910 * Returns: a pointer to the start of the valuetype boxed in this
5913 * This method will assert if the object passed is not a valuetype.
5916 mono_object_unbox (MonoObject *obj)
5918 MONO_REQ_GC_UNSAFE_MODE;
5920 /* add assert for valuetypes? */
5921 g_assert (obj->vtable->klass->valuetype);
5922 return ((char*)obj) + sizeof (MonoObject);
5926 * mono_object_isinst:
5928 * @klass: a pointer to a class
5930 * Returns: @obj if @obj is derived from @klass
5933 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5935 MONO_REQ_GC_UNSAFE_MODE;
5938 mono_class_init (klass);
5940 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5941 return mono_object_isinst_mbyref (obj, klass);
5946 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5950 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5952 MONO_REQ_GC_UNSAFE_MODE;
5962 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5963 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5967 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5968 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5971 MonoClass *oklass = vt->klass;
5972 if (mono_class_is_transparent_proxy (oklass))
5973 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5975 mono_class_setup_supertypes (klass);
5976 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5979 #ifndef DISABLE_REMOTING
5980 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5982 MonoDomain *domain = mono_domain_get ();
5984 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5985 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5986 MonoMethod *im = NULL;
5989 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5991 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
5992 im = mono_object_get_virtual_method (rp, im);
5995 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
5996 mono_error_raise_exception (&error); /* FIXME don't raise here */
5999 res = mono_runtime_invoke_checked (im, rp, pa, &error);
6000 mono_error_raise_exception (&error); /* FIXME don't raise here */
6002 if (*(MonoBoolean *) mono_object_unbox(res)) {
6003 /* Update the vtable of the remote type, so it can safely cast to this new type */
6004 mono_upgrade_remote_class (domain, obj, klass);
6008 #endif /* DISABLE_REMOTING */
6013 * mono_object_castclass_mbyref:
6015 * @klass: a pointer to a class
6017 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
6020 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
6022 MONO_REQ_GC_UNSAFE_MODE;
6024 if (!obj) return NULL;
6025 if (mono_object_isinst_mbyref (obj, klass)) return obj;
6027 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
6029 "InvalidCastException"));
6034 MonoDomain *orig_domain;
6040 str_lookup (MonoDomain *domain, gpointer user_data)
6042 MONO_REQ_GC_UNSAFE_MODE;
6044 LDStrInfo *info = (LDStrInfo *)user_data;
6045 if (info->res || domain == info->orig_domain)
6047 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6051 mono_string_get_pinned (MonoString *str, MonoError *error)
6053 MONO_REQ_GC_UNSAFE_MODE;
6055 mono_error_init (error);
6057 /* We only need to make a pinned version of a string if this is a moving GC */
6058 if (!mono_gc_is_moving ())
6062 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6063 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6065 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6066 news->length = mono_string_length (str);
6068 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6074 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6076 MONO_REQ_GC_UNSAFE_MODE;
6078 MonoGHashTable *ldstr_table;
6079 MonoString *s, *res;
6082 mono_error_init (error);
6084 domain = ((MonoObject *)str)->vtable->domain;
6085 ldstr_table = domain->ldstr_table;
6087 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6093 /* Allocate outside the lock */
6095 s = mono_string_get_pinned (str, error);
6096 return_val_if_nok (error, NULL);
6099 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6104 mono_g_hash_table_insert (ldstr_table, s, s);
6109 LDStrInfo ldstr_info;
6110 ldstr_info.orig_domain = domain;
6111 ldstr_info.ins = str;
6112 ldstr_info.res = NULL;
6114 mono_domain_foreach (str_lookup, &ldstr_info);
6115 if (ldstr_info.res) {
6117 * the string was already interned in some other domain:
6118 * intern it in the current one as well.
6120 mono_g_hash_table_insert (ldstr_table, str, str);
6130 * mono_string_is_interned:
6131 * @o: String to probe
6133 * Returns whether the string has been interned.
6136 mono_string_is_interned (MonoString *o)
6139 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6140 /* This function does not fail. */
6141 mono_error_assert_ok (&error);
6146 * mono_string_intern:
6147 * @o: String to intern
6149 * Interns the string passed.
6150 * Returns: The interned string.
6153 mono_string_intern (MonoString *str)
6156 MonoString *result = mono_string_intern_checked (str, &error);
6157 mono_error_assert_ok (&error);
6162 * mono_string_intern_checked:
6163 * @o: String to intern
6164 * @error: set on error.
6166 * Interns the string passed.
6167 * Returns: The interned string. On failure returns NULL and sets @error
6170 mono_string_intern_checked (MonoString *str, MonoError *error)
6172 MONO_REQ_GC_UNSAFE_MODE;
6174 mono_error_init (error);
6176 return mono_string_is_interned_lookup (str, TRUE, error);
6181 * @domain: the domain where the string will be used.
6182 * @image: a metadata context
6183 * @idx: index into the user string table.
6185 * Implementation for the ldstr opcode.
6186 * Returns: a loaded string from the @image/@idx combination.
6189 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6191 MONO_REQ_GC_UNSAFE_MODE;
6193 if (image->dynamic) {
6194 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
6197 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6198 return NULL; /*FIXME we should probably be raising an exception here*/
6199 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
6204 * mono_ldstr_metadata_sig
6205 * @domain: the domain for the string
6206 * @sig: the signature of a metadata string
6208 * Returns: a MonoString for a string stored in the metadata
6211 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
6213 MONO_REQ_GC_UNSAFE_MODE;
6216 const char *str = sig;
6217 MonoString *o, *interned;
6220 len2 = mono_metadata_decode_blob_size (str, &str);
6223 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, &error);
6224 mono_error_raise_exception (&error); /* FIXME don't raise here */
6225 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6228 guint16 *p2 = (guint16*)mono_string_chars (o);
6229 for (i = 0; i < len2; ++i) {
6230 *p2 = GUINT16_FROM_LE (*p2);
6236 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6239 return interned; /* o will get garbage collected */
6241 o = mono_string_get_pinned (o, &error);
6242 mono_error_raise_exception (&error); /* FIXME don't raise here */
6245 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6247 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6257 * mono_string_to_utf8:
6258 * @s: a System.String
6260 * Returns the UTF8 representation for @s.
6261 * The resulting buffer needs to be freed with mono_free().
6263 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6266 mono_string_to_utf8 (MonoString *s)
6268 MONO_REQ_GC_UNSAFE_MODE;
6271 char *result = mono_string_to_utf8_checked (s, &error);
6273 if (!mono_error_ok (&error))
6274 mono_error_raise_exception (&error);
6279 * mono_string_to_utf8_checked:
6280 * @s: a System.String
6281 * @error: a MonoError.
6283 * Converts a MonoString to its UTF8 representation. May fail; check
6284 * @error to determine whether the conversion was successful.
6285 * The resulting buffer should be freed with mono_free().
6288 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6290 MONO_REQ_GC_UNSAFE_MODE;
6294 GError *gerror = NULL;
6296 mono_error_init (error);
6302 return g_strdup ("");
6304 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6306 mono_error_set_argument (error, "string", "%s", gerror->message);
6307 g_error_free (gerror);
6310 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6311 if (s->length > written) {
6312 /* allocate the total length and copy the part of the string that has been converted */
6313 char *as2 = (char *)g_malloc0 (s->length);
6314 memcpy (as2, as, written);
6323 * mono_string_to_utf8_ignore:
6326 * Converts a MonoString to its UTF8 representation. Will ignore
6327 * invalid surrogate pairs.
6328 * The resulting buffer should be freed with mono_free().
6332 mono_string_to_utf8_ignore (MonoString *s)
6334 MONO_REQ_GC_UNSAFE_MODE;
6343 return g_strdup ("");
6345 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6347 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6348 if (s->length > written) {
6349 /* allocate the total length and copy the part of the string that has been converted */
6350 char *as2 = (char *)g_malloc0 (s->length);
6351 memcpy (as2, as, written);
6360 * mono_string_to_utf8_image_ignore:
6361 * @s: a System.String
6363 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6366 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
6368 MONO_REQ_GC_UNSAFE_MODE;
6370 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
6374 * mono_string_to_utf8_mp_ignore:
6375 * @s: a System.String
6377 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
6380 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
6382 MONO_REQ_GC_UNSAFE_MODE;
6384 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
6389 * mono_string_to_utf16:
6392 * Return an null-terminated array of the utf-16 chars
6393 * contained in @s. The result must be freed with g_free().
6394 * This is a temporary helper until our string implementation
6395 * is reworked to always include the null terminating char.
6398 mono_string_to_utf16 (MonoString *s)
6400 MONO_REQ_GC_UNSAFE_MODE;
6407 as = (char *)g_malloc ((s->length * 2) + 2);
6408 as [(s->length * 2)] = '\0';
6409 as [(s->length * 2) + 1] = '\0';
6412 return (gunichar2 *)(as);
6415 memcpy (as, mono_string_chars(s), s->length * 2);
6416 return (gunichar2 *)(as);
6420 * mono_string_to_utf32:
6423 * Return an null-terminated array of the UTF-32 (UCS-4) chars
6424 * contained in @s. The result must be freed with g_free().
6427 mono_string_to_utf32 (MonoString *s)
6429 MONO_REQ_GC_UNSAFE_MODE;
6431 mono_unichar4 *utf32_output = NULL;
6432 GError *error = NULL;
6433 glong items_written;
6438 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
6441 g_error_free (error);
6443 return utf32_output;
6447 * mono_string_from_utf16:
6448 * @data: the UTF16 string (LPWSTR) to convert
6450 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
6452 * Returns: a MonoString.
6455 mono_string_from_utf16 (gunichar2 *data)
6457 MONO_REQ_GC_UNSAFE_MODE;
6460 MonoString *res = NULL;
6461 MonoDomain *domain = mono_domain_get ();
6467 while (data [len]) len++;
6469 res = mono_string_new_utf16_checked (domain, data, len, &error);
6470 mono_error_raise_exception (&error); /* FIXME don't raise here */
6475 * mono_string_from_utf32:
6476 * @data: the UTF32 string (LPWSTR) to convert
6478 * Converts a UTF32 (UCS-4)to a MonoString.
6480 * Returns: a MonoString.
6483 mono_string_from_utf32 (mono_unichar4 *data)
6485 MONO_REQ_GC_UNSAFE_MODE;
6487 MonoString* result = NULL;
6488 mono_unichar2 *utf16_output = NULL;
6489 GError *error = NULL;
6490 glong items_written;
6496 while (data [len]) len++;
6498 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
6501 g_error_free (error);
6503 result = mono_string_from_utf16 (utf16_output);
6504 g_free (utf16_output);
6509 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
6511 MONO_REQ_GC_UNSAFE_MODE;
6518 r = mono_string_to_utf8_ignore (s);
6520 r = mono_string_to_utf8_checked (s, error);
6521 if (!mono_error_ok (error))
6528 len = strlen (r) + 1;
6530 mp_s = (char *)mono_mempool_alloc (mp, len);
6532 mp_s = (char *)mono_image_alloc (image, len);
6534 memcpy (mp_s, r, len);
6542 * mono_string_to_utf8_image:
6543 * @s: a System.String
6545 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
6548 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
6550 MONO_REQ_GC_UNSAFE_MODE;
6552 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
6556 * mono_string_to_utf8_mp:
6557 * @s: a System.String
6559 * Same as mono_string_to_utf8, but allocate the string from a mempool.
6562 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
6564 MONO_REQ_GC_UNSAFE_MODE;
6566 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
6570 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
6573 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
6575 eh_callbacks = *cbs;
6578 MonoRuntimeExceptionHandlingCallbacks *
6579 mono_get_eh_callbacks (void)
6581 return &eh_callbacks;
6585 * mono_raise_exception:
6586 * @ex: exception object
6588 * Signal the runtime that the exception @ex has been raised in unmanaged code.
6591 mono_raise_exception (MonoException *ex)
6593 MONO_REQ_GC_UNSAFE_MODE;
6596 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
6597 * that will cause gcc to omit the function epilog, causing problems when
6598 * the JIT tries to walk the stack, since the return address on the stack
6599 * will point into the next function in the executable, not this one.
6601 eh_callbacks.mono_raise_exception (ex);
6605 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
6607 MONO_REQ_GC_UNSAFE_MODE;
6609 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
6613 * mono_wait_handle_new:
6614 * @domain: Domain where the object will be created
6615 * @handle: Handle for the wait handle
6617 * Returns: A new MonoWaitHandle created in the given domain for the given handle
6620 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
6622 MONO_REQ_GC_UNSAFE_MODE;
6625 MonoWaitHandle *res;
6626 gpointer params [1];
6627 static MonoMethod *handle_set;
6629 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, &error);
6630 mono_error_raise_exception (&error); /* FIXME don't raise here */
6632 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
6634 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
6636 params [0] = &handle;
6638 mono_runtime_invoke_checked (handle_set, res, params, &error);
6639 mono_error_raise_exception (&error); /* FIXME don't raise here */
6645 mono_wait_handle_get_handle (MonoWaitHandle *handle)
6647 MONO_REQ_GC_UNSAFE_MODE;
6649 static MonoClassField *f_safe_handle = NULL;
6652 if (!f_safe_handle) {
6653 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
6654 g_assert (f_safe_handle);
6657 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
6663 mono_runtime_capture_context (MonoDomain *domain)
6665 MONO_REQ_GC_UNSAFE_MODE;
6667 RuntimeInvokeFunction runtime_invoke;
6669 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
6670 MonoMethod *method = mono_get_context_capture_method ();
6671 MonoMethod *wrapper;
6674 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
6675 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
6676 domain->capture_context_method = mono_compile_method (method);
6679 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
6681 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
6684 * mono_async_result_new:
6685 * @domain:domain where the object will be created.
6686 * @handle: wait handle.
6687 * @state: state to pass to AsyncResult
6688 * @data: C closure data.
6690 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6691 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6695 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6697 MONO_REQ_GC_UNSAFE_MODE;
6700 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, &error);
6701 mono_error_raise_exception (&error); /* FIXME don't raise here */
6702 MonoObject *context = mono_runtime_capture_context (domain);
6703 /* we must capture the execution context from the original thread */
6705 MONO_OBJECT_SETREF (res, execution_context, context);
6706 /* note: result may be null if the flow is suppressed */
6709 res->data = (void **)data;
6710 MONO_OBJECT_SETREF (res, object_data, object_data);
6711 MONO_OBJECT_SETREF (res, async_state, state);
6713 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6715 res->sync_completed = FALSE;
6716 res->completed = FALSE;
6722 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
6724 MONO_REQ_GC_UNSAFE_MODE;
6731 g_assert (ares->async_delegate);
6733 ac = (MonoAsyncCall*) ares->object_data;
6735 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
6737 gpointer wait_event = NULL;
6739 ac->msg->exc = NULL;
6740 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
6741 MONO_OBJECT_SETREF (ac, res, res);
6743 mono_monitor_enter ((MonoObject*) ares);
6744 ares->completed = 1;
6746 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6747 mono_monitor_exit ((MonoObject*) ares);
6749 if (wait_event != NULL)
6750 SetEvent (wait_event);
6752 if (ac->cb_method) {
6753 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
6754 mono_error_raise_exception (&error);
6762 mono_message_init (MonoDomain *domain,
6763 MonoMethodMessage *this_obj,
6764 MonoReflectionMethod *method,
6765 MonoArray *out_args)
6767 MONO_REQ_GC_UNSAFE_MODE;
6769 static MonoClass *object_array_klass;
6770 static MonoClass *byte_array_klass;
6771 static MonoClass *string_array_klass;
6773 MonoMethodSignature *sig = mono_method_signature (method->method);
6780 if (!object_array_klass) {
6783 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6785 byte_array_klass = klass;
6787 klass = mono_array_class_get (mono_defaults.string_class, 1);
6789 string_array_klass = klass;
6791 klass = mono_array_class_get (mono_defaults.object_class, 1);
6794 mono_atomic_store_release (&object_array_klass, klass);
6797 MONO_OBJECT_SETREF (this_obj, method, method);
6799 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, &error);
6800 mono_error_raise_exception (&error); /* FIXME don't raise here */
6802 MONO_OBJECT_SETREF (this_obj, args, arr);
6804 arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, &error);
6805 mono_error_raise_exception (&error); /* FIXME don't raise here */
6807 MONO_OBJECT_SETREF (this_obj, arg_types, arr);
6809 this_obj->async_result = NULL;
6810 this_obj->call_type = CallType_Sync;
6812 names = g_new (char *, sig->param_count);
6813 mono_method_get_param_names (method->method, (const char **) names);
6815 arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, &error);
6816 mono_error_raise_exception (&error); /* FIXME don't raise here */
6818 MONO_OBJECT_SETREF (this_obj, names, arr);
6820 for (i = 0; i < sig->param_count; i++) {
6821 name = mono_string_new (domain, names [i]);
6822 mono_array_setref (this_obj->names, i, name);
6826 for (i = 0, j = 0; i < sig->param_count; i++) {
6827 if (sig->params [i]->byref) {
6829 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
6830 mono_array_setref (this_obj->args, i, arg);
6834 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6838 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6841 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
6845 #ifndef DISABLE_REMOTING
6847 * mono_remoting_invoke:
6848 * @real_proxy: pointer to a RealProxy object
6849 * @msg: The MonoMethodMessage to execute
6850 * @exc: used to store exceptions
6851 * @out_args: used to store output arguments
6853 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6854 * IMessage interface and it is not trivial to extract results from there. So
6855 * we call an helper method PrivateInvoke instead of calling
6856 * RealProxy::Invoke() directly.
6858 * Returns: the result object.
6861 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
6863 MONO_REQ_GC_UNSAFE_MODE;
6866 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6871 mono_error_init (error);
6873 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6876 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6878 mono_error_set_generic_error (error, "System", "NotSupportedException", "Linked away.");
6881 real_proxy->vtable->domain->private_invoke_method = im;
6884 pa [0] = real_proxy;
6889 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
6890 return_val_if_nok (error, NULL);
6897 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6898 MonoObject **exc, MonoArray **out_args)
6900 MONO_REQ_GC_UNSAFE_MODE;
6902 static MonoClass *object_array_klass;
6906 MonoMethodSignature *sig;
6909 int i, j, outarg_count = 0;
6911 #ifndef DISABLE_REMOTING
6912 if (target && mono_object_is_transparent_proxy (target)) {
6913 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6914 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6915 target = tp->rp->unwrapped_server;
6917 ret = mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, &error);
6918 mono_error_raise_exception (&error); /* FIXME don't raise here */
6925 domain = mono_domain_get ();
6926 method = msg->method->method;
6927 sig = mono_method_signature (method);
6929 for (i = 0; i < sig->param_count; i++) {
6930 if (sig->params [i]->byref)
6934 if (!object_array_klass) {
6937 klass = mono_array_class_get (mono_defaults.object_class, 1);
6940 mono_memory_barrier ();
6941 object_array_klass = klass;
6944 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, &error);
6945 mono_error_raise_exception (&error); /* FIXME don't raise here */
6947 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
6950 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6952 for (i = 0, j = 0; i < sig->param_count; i++) {
6953 if (sig->params [i]->byref) {
6955 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
6956 mono_array_setref (*out_args, j, arg);
6965 * mono_object_to_string:
6967 * @exc: Any exception thrown by ToString (). May be NULL.
6969 * Returns: the result of calling ToString () on an object.
6972 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6974 MONO_REQ_GC_UNSAFE_MODE;
6976 static MonoMethod *to_string = NULL;
6985 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6987 method = mono_object_get_virtual_method (obj, to_string);
6989 // Unbox value type if needed
6990 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6991 target = mono_object_unbox (obj);
6995 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
6996 if (*exc == NULL && !mono_error_ok (&error))
6997 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
6999 mono_error_cleanup (&error);
7001 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7002 mono_error_raise_exception (&error); /* FIXME don't raise here */
7009 * mono_print_unhandled_exception:
7010 * @exc: The exception
7012 * Prints the unhandled exception.
7015 mono_print_unhandled_exception (MonoObject *exc)
7017 MONO_REQ_GC_UNSAFE_MODE;
7020 char *message = (char*)"";
7021 gboolean free_message = FALSE;
7024 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7025 message = g_strdup ("OutOfMemoryException");
7026 free_message = TRUE;
7027 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7028 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7029 free_message = TRUE;
7032 if (((MonoException*)exc)->native_trace_ips) {
7033 message = mono_exception_get_native_backtrace ((MonoException*)exc);
7034 free_message = TRUE;
7036 MonoObject *other_exc = NULL;
7037 str = mono_object_to_string (exc, &other_exc);
7039 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7040 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7042 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7043 original_backtrace, nested_backtrace);
7045 g_free (original_backtrace);
7046 g_free (nested_backtrace);
7047 free_message = TRUE;
7049 message = mono_string_to_utf8_checked (str, &error);
7050 if (!mono_error_ok (&error)) {
7051 mono_error_cleanup (&error);
7052 message = (char *) "";
7054 free_message = TRUE;
7061 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7062 * exc->vtable->klass->name, message);
7064 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7071 * mono_delegate_ctor:
7072 * @this: pointer to an uninitialized delegate object
7073 * @target: target object
7074 * @addr: pointer to native code
7077 * Initialize a delegate and sets a specific method, not the one
7078 * associated with addr. This is useful when sharing generic code.
7079 * In that case addr will most probably not be associated with the
7080 * correct instantiation of the method.
7083 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
7085 MONO_REQ_GC_UNSAFE_MODE;
7087 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7089 g_assert (this_obj);
7092 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7095 delegate->method = method;
7097 mono_stats.delegate_creations++;
7099 #ifndef DISABLE_REMOTING
7100 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7102 method = mono_marshal_get_remoting_invoke (method);
7103 delegate->method_ptr = mono_compile_method (method);
7104 MONO_OBJECT_SETREF (delegate, target, target);
7108 delegate->method_ptr = addr;
7109 MONO_OBJECT_SETREF (delegate, target, target);
7112 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7113 if (callbacks.init_delegate)
7114 callbacks.init_delegate (delegate);
7118 * mono_delegate_ctor:
7119 * @this: pointer to an uninitialized delegate object
7120 * @target: target object
7121 * @addr: pointer to native code
7123 * This is used to initialize a delegate.
7126 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
7128 MONO_REQ_GC_UNSAFE_MODE;
7130 MonoDomain *domain = mono_domain_get ();
7132 MonoMethod *method = NULL;
7136 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7138 if (!ji && domain != mono_get_root_domain ())
7139 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7141 method = mono_jit_info_get_method (ji);
7142 g_assert (!method->klass->generic_container);
7145 mono_delegate_ctor_with_method (this_obj, target, addr, method);
7149 * mono_method_call_message_new:
7150 * @method: method to encapsulate
7151 * @params: parameters to the method
7152 * @invoke: optional, delegate invoke.
7153 * @cb: async callback delegate.
7154 * @state: state passed to the async callback.
7156 * Translates arguments pointers into a MonoMethodMessage.
7159 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7160 MonoDelegate **cb, MonoObject **state)
7162 MONO_REQ_GC_UNSAFE_MODE;
7166 MonoDomain *domain = mono_domain_get ();
7167 MonoMethodSignature *sig = mono_method_signature (method);
7168 MonoMethodMessage *msg;
7171 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7172 mono_error_raise_exception (&error); /* FIXME don't raise here */
7175 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, &error);
7176 mono_error_raise_exception (&error); /* FIXME don't raise here */
7177 mono_message_init (domain, msg, rm, NULL);
7178 count = sig->param_count - 2;
7180 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, &error);
7181 mono_error_raise_exception (&error); /* FIXME don't raise here */
7182 mono_message_init (domain, msg, rm, NULL);
7183 count = sig->param_count;
7186 for (i = 0; i < count; i++) {
7191 if (sig->params [i]->byref)
7192 vpos = *((gpointer *)params [i]);
7196 klass = mono_class_from_mono_type (sig->params [i]);
7198 if (klass->valuetype)
7199 arg = mono_value_box (domain, klass, vpos);
7201 arg = *((MonoObject **)vpos);
7203 mono_array_setref (msg->args, i, arg);
7206 if (cb != NULL && state != NULL) {
7207 *cb = *((MonoDelegate **)params [i]);
7209 *state = *((MonoObject **)params [i]);
7216 * mono_method_return_message_restore:
7218 * Restore results from message based processing back to arguments pointers
7221 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
7223 MONO_REQ_GC_UNSAFE_MODE;
7225 MonoMethodSignature *sig = mono_method_signature (method);
7226 int i, j, type, size, out_len;
7228 if (out_args == NULL)
7230 out_len = mono_array_length (out_args);
7234 for (i = 0, j = 0; i < sig->param_count; i++) {
7235 MonoType *pt = sig->params [i];
7240 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
7242 arg = (char *)mono_array_get (out_args, gpointer, j);
7245 g_assert (type != MONO_TYPE_VOID);
7247 if (MONO_TYPE_IS_REFERENCE (pt)) {
7248 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7251 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7252 size = mono_class_value_size (klass, NULL);
7253 if (klass->has_references)
7254 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7256 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7258 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7259 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7268 #ifndef DISABLE_REMOTING
7271 * mono_load_remote_field:
7272 * @this: pointer to an object
7273 * @klass: klass of the object containing @field
7274 * @field: the field to load
7275 * @res: a storage to store the result
7277 * This method is called by the runtime on attempts to load fields of
7278 * transparent proxy objects. @this points to such TP, @klass is the class of
7279 * the object containing @field. @res is a storage location which can be
7280 * used to store the result.
7282 * Returns: an address pointing to the value of field.
7285 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
7287 MONO_REQ_GC_UNSAFE_MODE;
7291 static MonoMethod *getter = NULL;
7292 MonoDomain *domain = mono_domain_get ();
7293 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7294 MonoClass *field_class;
7295 MonoMethodMessage *msg;
7296 MonoArray *out_args;
7300 g_assert (mono_object_is_transparent_proxy (this_obj));
7301 g_assert (res != NULL);
7303 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7304 mono_field_get_value (tp->rp->unwrapped_server, field, res);
7309 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7311 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7314 field_class = mono_class_from_mono_type (field->type);
7316 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7317 mono_error_raise_exception (&error); /* FIXME don't raise here */
7318 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7319 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7320 mono_error_raise_exception (&error); /* FIXME don't raise here */
7321 mono_message_init (domain, msg, rm, out_args);
7323 full_name = mono_type_get_full_name (klass);
7324 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7325 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7328 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, &error);
7329 mono_error_raise_exception (&error); /* FIXME don't raise here */
7331 if (exc) mono_raise_exception ((MonoException *)exc);
7333 if (mono_array_length (out_args) == 0)
7336 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
7338 if (field_class->valuetype) {
7339 return ((char *)*res) + sizeof (MonoObject);
7345 * mono_load_remote_field_new:
7350 * Missing documentation.
7353 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
7355 MONO_REQ_GC_UNSAFE_MODE;
7359 static MonoMethod *getter = NULL;
7360 MonoDomain *domain = mono_domain_get ();
7361 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7362 MonoClass *field_class;
7363 MonoMethodMessage *msg;
7364 MonoArray *out_args;
7365 MonoObject *exc, *res;
7368 g_assert (mono_object_is_transparent_proxy (this_obj));
7370 field_class = mono_class_from_mono_type (field->type);
7372 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7374 if (field_class->valuetype) {
7375 res = mono_object_new_checked (domain, field_class, &error);
7376 mono_error_raise_exception (&error); /* FIXME don't raise here */
7377 val = ((gchar *) res) + sizeof (MonoObject);
7381 mono_field_get_value (tp->rp->unwrapped_server, field, val);
7386 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7388 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7391 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7392 mono_error_raise_exception (&error); /* FIXME don't raise here */
7393 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7395 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7396 mono_error_raise_exception (&error); /* FIXME don't raise here */
7397 mono_message_init (domain, msg, rm, out_args);
7399 full_name = mono_type_get_full_name (klass);
7400 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7401 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7404 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, &error);
7405 mono_error_raise_exception (&error); /* FIXME don't raise here */
7407 if (exc) mono_raise_exception ((MonoException *)exc);
7409 if (mono_array_length (out_args) == 0)
7412 res = mono_array_get (out_args, MonoObject *, 0);
7418 * mono_store_remote_field:
7419 * @this_obj: pointer to an object
7420 * @klass: klass of the object containing @field
7421 * @field: the field to load
7422 * @val: the value/object to store
7424 * This method is called by the runtime on attempts to store fields of
7425 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
7426 * the object containing @field. @val is the new value to store in @field.
7429 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
7431 MONO_REQ_GC_UNSAFE_MODE;
7435 static MonoMethod *setter = NULL;
7436 MonoDomain *domain = mono_domain_get ();
7437 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7438 MonoClass *field_class;
7439 MonoMethodMessage *msg;
7440 MonoArray *out_args;
7445 g_assert (mono_object_is_transparent_proxy (this_obj));
7447 field_class = mono_class_from_mono_type (field->type);
7449 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7450 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
7451 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
7456 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7458 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7461 if (field_class->valuetype)
7462 arg = mono_value_box (domain, field_class, val);
7464 arg = *((MonoObject **)val);
7467 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7468 mono_error_raise_exception (&error); /* FIXME don't raise here */
7469 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7470 mono_error_raise_exception (&error); /* FIXME don't raise here */
7471 mono_message_init (domain, msg, rm, NULL);
7473 full_name = mono_type_get_full_name (klass);
7474 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7475 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7476 mono_array_setref (msg->args, 2, arg);
7479 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, &error);
7480 mono_error_raise_exception (&error); /* FIXME don't raise here */
7482 if (exc) mono_raise_exception ((MonoException *)exc);
7486 * mono_store_remote_field_new:
7492 * Missing documentation
7495 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
7497 MONO_REQ_GC_UNSAFE_MODE;
7501 static MonoMethod *setter = NULL;
7502 MonoDomain *domain = mono_domain_get ();
7503 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7504 MonoClass *field_class;
7505 MonoMethodMessage *msg;
7506 MonoArray *out_args;
7510 g_assert (mono_object_is_transparent_proxy (this_obj));
7512 field_class = mono_class_from_mono_type (field->type);
7514 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7515 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
7516 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
7521 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7523 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7526 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7527 mono_error_raise_exception (&error); /* FIXME don't raise here */
7528 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7529 mono_error_raise_exception (&error); /* FIXME don't raise here */
7530 mono_message_init (domain, msg, rm, NULL);
7532 full_name = mono_type_get_full_name (klass);
7533 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7534 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7535 mono_array_setref (msg->args, 2, arg);
7538 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, &error);
7539 mono_error_raise_exception (&error); /* FIXME don't raise here */
7541 if (exc) mono_raise_exception ((MonoException *)exc);
7546 * mono_create_ftnptr:
7548 * Given a function address, create a function descriptor for it.
7549 * This is only needed on some platforms.
7552 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
7554 return callbacks.create_ftnptr (domain, addr);
7558 * mono_get_addr_from_ftnptr:
7560 * Given a pointer to a function descriptor, return the function address.
7561 * This is only needed on some platforms.
7564 mono_get_addr_from_ftnptr (gpointer descr)
7566 return callbacks.get_addr_from_ftnptr (descr);
7570 * mono_string_chars:
7573 * Returns a pointer to the UCS16 characters stored in the MonoString
7576 mono_string_chars (MonoString *s)
7578 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
7584 * mono_string_length:
7587 * Returns the lenght in characters of the string
7590 mono_string_length (MonoString *s)
7592 MONO_REQ_GC_UNSAFE_MODE;
7598 * mono_array_length:
7599 * @array: a MonoArray*
7601 * Returns the total number of elements in the array. This works for
7602 * both vectors and multidimensional arrays.
7605 mono_array_length (MonoArray *array)
7607 MONO_REQ_GC_UNSAFE_MODE;
7609 return array->max_length;
7613 * mono_array_addr_with_size:
7614 * @array: a MonoArray*
7615 * @size: size of the array elements
7616 * @idx: index into the array
7618 * Use this function to obtain the address for the @idx item on the
7619 * @array containing elements of size @size.
7621 * This method performs no bounds checking or type checking.
7623 * Returns the address of the @idx element in the array.
7626 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
7628 MONO_REQ_GC_UNSAFE_MODE;
7630 return ((char*)(array)->vector) + size * idx;
7635 mono_glist_to_array (GList *list, MonoClass *eclass)
7637 MonoDomain *domain = mono_domain_get ();
7644 len = g_list_length (list);
7645 res = mono_array_new (domain, eclass, len);
7647 for (i = 0; list; list = list->next, i++)
7648 mono_array_set (res, gpointer, i, list->data);
7655 * The following section is purely to declare prototypes and
7656 * document the API, as these C files are processed by our
7662 * @array: array to alter
7663 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
7664 * @index: index into the array
7665 * @value: value to set
7667 * Value Type version: This sets the @index's element of the @array
7668 * with elements of size sizeof(type) to the provided @value.
7670 * This macro does not attempt to perform type checking or bounds checking.
7672 * Use this to set value types in a `MonoArray`.
7674 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
7679 * mono_array_setref:
7680 * @array: array to alter
7681 * @index: index into the array
7682 * @value: value to set
7684 * Reference Type version: This sets the @index's element of the
7685 * @array with elements of size sizeof(type) to the provided @value.
7687 * This macro does not attempt to perform type checking or bounds checking.
7689 * Use this to reference types in a `MonoArray`.
7691 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
7697 * @array: array on which to operate on
7698 * @element_type: C element type (example: MonoString *, int, MonoObject *)
7699 * @index: index into the array
7701 * Use this macro to retrieve the @index element of an @array and
7702 * extract the value assuming that the elements of the array match
7703 * the provided type value.
7705 * This method can be used with both arrays holding value types and
7706 * reference types. For reference types, the @type parameter should
7707 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
7709 * This macro does not attempt to perform type checking or bounds checking.
7711 * Returns: The element at the @index position in the @array.
7713 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)