[runtime] When interning strings, allocate without holding the ldstr lock.
[mono-project.git] / mono / metadata / object.c
blobdcd321e8c520e59f695624ef176649cae2aeb93f
1 /*
2 * object.c: Object creation for the Mono runtime
4 * Author:
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)
12 #include <config.h>
13 #ifdef HAVE_ALLOCA_H
14 #include <alloca.h>
15 #endif
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
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-internal.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/threadpool.h>
31 #include <mono/metadata/marshal.h>
32 #include "mono/metadata/debug-helpers.h"
33 #include "mono/metadata/marshal.h"
34 #include <mono/metadata/threads.h>
35 #include <mono/metadata/threads-types.h>
36 #include <mono/metadata/environment.h>
37 #include "mono/metadata/profiler-private.h"
38 #include "mono/metadata/security-manager.h"
39 #include "mono/metadata/mono-debug-debugger.h"
40 #include <mono/metadata/gc-internal.h>
41 #include <mono/metadata/verify-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 "cominterop.h"
48 #ifdef HAVE_BOEHM_GC
49 #define NEED_TO_ZERO_PTRFREE 1
50 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
51 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
52 #ifdef HAVE_GC_GCJ_MALLOC
53 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
54 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
55 #else
56 #define GC_NO_DESCRIPTOR (NULL)
57 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
58 #endif
59 #else
60 #ifdef HAVE_SGEN_GC
61 #define GC_NO_DESCRIPTOR (NULL)
62 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
63 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
64 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
65 #else
66 #define NEED_TO_ZERO_PTRFREE 1
67 #define GC_NO_DESCRIPTOR (NULL)
68 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
69 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
70 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
71 #endif
72 #endif
74 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
75 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
77 static void
78 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
80 static MonoString*
81 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
83 static void
84 free_main_args (void);
86 static char *
87 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
90 #define ldstr_lock() mono_mutex_lock (&ldstr_section)
91 #define ldstr_unlock() mono_mutex_unlock (&ldstr_section)
92 static mono_mutex_t ldstr_section;
94 static gboolean profile_allocs = TRUE;
96 void
97 mono_runtime_object_init (MonoObject *this)
99 MonoMethod *method = NULL;
100 MonoClass *klass = this->vtable->klass;
102 method = mono_class_get_method_from_name (klass, ".ctor", 0);
103 if (!method)
104 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
106 if (method->klass->valuetype)
107 this = mono_object_unbox (this);
108 mono_runtime_invoke (method, this, NULL, NULL);
111 /* The pseudo algorithm for type initialization from the spec
112 Note it doesn't say anything about domains - only threads.
114 2. If the type is initialized you are done.
115 2.1. If the type is not yet initialized, try to take an
116 initialization lock.
117 2.2. If successful, record this thread as responsible for
118 initializing the type and proceed to step 2.3.
119 2.2.1. If not, see whether this thread or any thread
120 waiting for this thread to complete already holds the lock.
121 2.2.2. If so, return since blocking would create a deadlock. This thread
122 will now see an incompletely initialized state for the type,
123 but no deadlock will arise.
124 2.2.3 If not, block until the type is initialized then return.
125 2.3 Initialize the parent type and then all interfaces implemented
126 by this type.
127 2.4 Execute the type initialization code for this type.
128 2.5 Mark the type as initialized, release the initialization lock,
129 awaken any threads waiting for this type to be initialized,
130 and return.
134 typedef struct
136 guint32 initializing_tid;
137 guint32 waiting_count;
138 gboolean done;
139 mono_mutex_t initialization_section;
140 } TypeInitializationLock;
142 /* for locking access to type_initialization_hash and blocked_thread_hash */
143 #define mono_type_initialization_lock() mono_mutex_lock (&type_initialization_section)
144 #define mono_type_initialization_unlock() mono_mutex_unlock (&type_initialization_section)
145 static mono_mutex_t type_initialization_section;
147 /* from vtable to lock */
148 static GHashTable *type_initialization_hash;
150 /* from thread id to thread id being waited on */
151 static GHashTable *blocked_thread_hash;
153 /* Main thread */
154 static MonoThread *main_thread;
156 /* Functions supplied by the runtime */
157 static MonoRuntimeCallbacks callbacks;
160 * mono_thread_set_main:
161 * @thread: thread to set as the main thread
163 * This function can be used to instruct the runtime to treat @thread
164 * as the main thread, ie, the thread that would normally execute the Main()
165 * method. This basically means that at the end of @thread, the runtime will
166 * wait for the existing foreground threads to quit and other such details.
168 void
169 mono_thread_set_main (MonoThread *thread)
171 static gboolean registered = FALSE;
173 if (!registered) {
174 MONO_GC_REGISTER_ROOT_SINGLE (main_thread);
175 registered = TRUE;
178 main_thread = thread;
181 MonoThread*
182 mono_thread_get_main (void)
184 return main_thread;
187 void
188 mono_type_initialization_init (void)
190 mono_mutex_init_recursive (&type_initialization_section);
191 type_initialization_hash = g_hash_table_new (NULL, NULL);
192 blocked_thread_hash = g_hash_table_new (NULL, NULL);
193 mono_mutex_init_recursive (&ldstr_section);
196 void
197 mono_type_initialization_cleanup (void)
199 #if 0
200 /* This is causing race conditions with
201 * mono_release_type_locks
203 mono_mutex_destroy (&type_initialization_section);
204 g_hash_table_destroy (type_initialization_hash);
205 type_initialization_hash = NULL;
206 #endif
207 mono_mutex_destroy (&ldstr_section);
208 g_hash_table_destroy (blocked_thread_hash);
209 blocked_thread_hash = NULL;
211 free_main_args ();
215 * get_type_init_exception_for_vtable:
217 * Return the stored type initialization exception for VTABLE.
219 static MonoException*
220 get_type_init_exception_for_vtable (MonoVTable *vtable)
222 MonoDomain *domain = vtable->domain;
223 MonoClass *klass = vtable->klass;
224 MonoException *ex;
225 gchar *full_name;
227 if (!vtable->init_failed)
228 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
231 * If the initializing thread was rudely aborted, the exception is not stored
232 * in the hash.
234 ex = NULL;
235 mono_domain_lock (domain);
236 if (domain->type_init_exception_hash)
237 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
238 mono_domain_unlock (domain);
240 if (!ex) {
241 if (klass->name_space && *klass->name_space)
242 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
243 else
244 full_name = g_strdup (klass->name);
245 ex = mono_get_exception_type_initialization (full_name, NULL);
246 g_free (full_name);
249 return ex;
252 * mono_runtime_class_init:
253 * @vtable: vtable that needs to be initialized
255 * This routine calls the class constructor for @vtable.
257 void
258 mono_runtime_class_init (MonoVTable *vtable)
260 mono_runtime_class_init_full (vtable, TRUE);
264 * mono_runtime_class_init_full:
265 * @vtable that neeeds to be initialized
266 * @raise_exception is TRUE, exceptions are raised intead of returned
269 MonoException *
270 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
272 MonoException *exc;
273 MonoException *exc_to_throw;
274 MonoMethod *method = NULL;
275 MonoClass *klass;
276 gchar *full_name;
278 if (vtable->initialized)
279 return NULL;
281 exc = NULL;
282 klass = vtable->klass;
284 if (!klass->image->checked_module_cctor) {
285 mono_image_check_for_module_cctor (klass->image);
286 if (klass->image->has_module_cctor) {
287 MonoError error;
288 MonoClass *module_klass;
289 MonoVTable *module_vtable;
291 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, &error);
292 if (!module_klass) {
293 exc = mono_error_convert_to_exception (&error);
294 if (raise_exception)
295 mono_raise_exception (exc);
296 return exc;
299 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
300 if (!module_vtable)
301 return NULL;
302 exc = mono_runtime_class_init_full (module_vtable, raise_exception);
303 if (exc)
304 return exc;
307 method = mono_class_get_cctor (klass);
309 if (method) {
310 MonoDomain *domain = vtable->domain;
311 TypeInitializationLock *lock;
312 guint32 tid = GetCurrentThreadId();
313 int do_initialization = 0;
314 MonoDomain *last_domain = NULL;
316 mono_type_initialization_lock ();
317 /* double check... */
318 if (vtable->initialized) {
319 mono_type_initialization_unlock ();
320 return NULL;
322 if (vtable->init_failed) {
323 mono_type_initialization_unlock ();
325 /* The type initialization already failed once, rethrow the same exception */
326 if (raise_exception)
327 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
328 return get_type_init_exception_for_vtable (vtable);
330 lock = g_hash_table_lookup (type_initialization_hash, vtable);
331 if (lock == NULL) {
332 /* This thread will get to do the initialization */
333 if (mono_domain_get () != domain) {
334 /* Transfer into the target domain */
335 last_domain = mono_domain_get ();
336 if (!mono_domain_set (domain, FALSE)) {
337 vtable->initialized = 1;
338 mono_type_initialization_unlock ();
339 if (raise_exception)
340 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
341 return mono_get_exception_appdomain_unloaded ();
344 lock = g_malloc (sizeof(TypeInitializationLock));
345 mono_mutex_init_recursive (&lock->initialization_section);
346 lock->initializing_tid = tid;
347 lock->waiting_count = 1;
348 lock->done = FALSE;
349 /* grab the vtable lock while this thread still owns type_initialization_section */
350 mono_mutex_lock (&lock->initialization_section);
351 g_hash_table_insert (type_initialization_hash, vtable, lock);
352 do_initialization = 1;
353 } else {
354 gpointer blocked;
355 TypeInitializationLock *pending_lock;
357 if (lock->initializing_tid == tid || lock->done) {
358 mono_type_initialization_unlock ();
359 return NULL;
361 /* see if the thread doing the initialization is already blocked on this thread */
362 blocked = GUINT_TO_POINTER (lock->initializing_tid);
363 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
364 if (pending_lock->initializing_tid == tid) {
365 if (!pending_lock->done) {
366 mono_type_initialization_unlock ();
367 return NULL;
368 } else {
369 /* the thread doing the initialization is blocked on this thread,
370 but on a lock that has already been freed. It just hasn't got
371 time to awake */
372 break;
375 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
377 ++lock->waiting_count;
378 /* record the fact that we are waiting on the initializing thread */
379 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
381 mono_type_initialization_unlock ();
383 if (do_initialization) {
384 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
386 /* If the initialization failed, mark the class as unusable. */
387 /* Avoid infinite loops */
388 if (!(exc == NULL ||
389 (klass->image == mono_defaults.corlib &&
390 !strcmp (klass->name_space, "System") &&
391 !strcmp (klass->name, "TypeInitializationException")))) {
392 vtable->init_failed = 1;
394 if (klass->name_space && *klass->name_space)
395 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
396 else
397 full_name = g_strdup (klass->name);
398 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
399 g_free (full_name);
402 * Store the exception object so it could be thrown on subsequent
403 * accesses.
405 mono_domain_lock (domain);
406 if (!domain->type_init_exception_hash)
407 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
408 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
409 mono_domain_unlock (domain);
412 if (last_domain)
413 mono_domain_set (last_domain, TRUE);
414 lock->done = TRUE;
415 mono_mutex_unlock (&lock->initialization_section);
416 } else {
417 /* this just blocks until the initializing thread is done */
418 mono_mutex_lock (&lock->initialization_section);
419 mono_mutex_unlock (&lock->initialization_section);
422 mono_type_initialization_lock ();
423 if (lock->initializing_tid != tid)
424 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
425 --lock->waiting_count;
426 if (lock->waiting_count == 0) {
427 mono_mutex_destroy (&lock->initialization_section);
428 g_hash_table_remove (type_initialization_hash, vtable);
429 g_free (lock);
431 mono_memory_barrier ();
432 if (!vtable->init_failed)
433 vtable->initialized = 1;
434 mono_type_initialization_unlock ();
436 if (vtable->init_failed) {
437 /* Either we were the initializing thread or we waited for the initialization */
438 if (raise_exception)
439 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
440 return get_type_init_exception_for_vtable (vtable);
442 } else {
443 vtable->initialized = 1;
444 return NULL;
446 return NULL;
449 static
450 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
452 MonoVTable *vtable = (MonoVTable*)key;
454 TypeInitializationLock *lock = (TypeInitializationLock*) value;
455 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
456 lock->done = TRUE;
458 * Have to set this since it cannot be set by the normal code in
459 * mono_runtime_class_init (). In this case, the exception object is not stored,
460 * and get_type_init_exception_for_class () needs to be aware of this.
462 vtable->init_failed = 1;
463 mono_mutex_unlock (&lock->initialization_section);
464 --lock->waiting_count;
465 if (lock->waiting_count == 0) {
466 mono_mutex_destroy (&lock->initialization_section);
467 g_free (lock);
468 return TRUE;
471 return FALSE;
474 void
475 mono_release_type_locks (MonoInternalThread *thread)
477 mono_type_initialization_lock ();
478 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
479 mono_type_initialization_unlock ();
482 static gpointer
483 default_trampoline (MonoMethod *method)
485 return method;
488 static gpointer
489 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
491 g_assert_not_reached ();
493 return NULL;
496 #ifndef DISABLE_REMOTING
498 static gpointer
499 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
501 g_error ("remoting not installed");
502 return NULL;
505 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
506 #endif
508 static gpointer
509 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
511 g_assert_not_reached ();
512 return NULL;
515 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
516 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
517 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
518 static MonoImtThunkBuilder imt_thunk_builder = NULL;
519 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
520 #if (MONO_IMT_SIZE > 32)
521 #error "MONO_IMT_SIZE cannot be larger than 32"
522 #endif
524 void
525 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
527 memcpy (&callbacks, cbs, sizeof (*cbs));
530 MonoRuntimeCallbacks*
531 mono_get_runtime_callbacks (void)
533 return &callbacks;
536 void
537 mono_install_trampoline (MonoTrampoline func)
539 arch_create_jit_trampoline = func? func: default_trampoline;
542 void
543 mono_install_jump_trampoline (MonoJumpTrampoline func)
545 arch_create_jump_trampoline = func? func: default_jump_trampoline;
548 #ifndef DISABLE_REMOTING
549 void
550 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
552 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
554 #endif
556 void
557 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
559 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
562 void
563 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
564 imt_thunk_builder = func;
567 static MonoCompileFunc default_mono_compile_method = NULL;
570 * mono_install_compile_method:
571 * @func: function to install
573 * This is a VM internal routine
575 void
576 mono_install_compile_method (MonoCompileFunc func)
578 default_mono_compile_method = func;
582 * mono_compile_method:
583 * @method: The method to compile.
585 * This JIT-compiles the method, and returns the pointer to the native code
586 * produced.
588 gpointer
589 mono_compile_method (MonoMethod *method)
591 if (!default_mono_compile_method) {
592 g_error ("compile method called on uninitialized runtime");
593 return NULL;
595 return default_mono_compile_method (method);
598 gpointer
599 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
601 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
604 gpointer
605 mono_runtime_create_delegate_trampoline (MonoClass *klass)
607 return arch_create_delegate_trampoline (mono_domain_get (), klass);
610 static MonoFreeMethodFunc default_mono_free_method = NULL;
613 * mono_install_free_method:
614 * @func: pointer to the MonoFreeMethodFunc used to release a method
616 * This is an internal VM routine, it is used for the engines to
617 * register a handler to release the resources associated with a method.
619 * Methods are freed when no more references to the delegate that holds
620 * them are left.
622 void
623 mono_install_free_method (MonoFreeMethodFunc func)
625 default_mono_free_method = func;
629 * mono_runtime_free_method:
630 * @domain; domain where the method is hosted
631 * @method: method to release
633 * This routine is invoked to free the resources associated with
634 * a method that has been JIT compiled. This is used to discard
635 * methods that were used only temporarily (for example, used in marshalling)
638 void
639 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
641 if (default_mono_free_method != NULL)
642 default_mono_free_method (domain, method);
644 mono_method_clear_object (domain, method);
646 mono_free_method (method);
650 * The vtables in the root appdomain are assumed to be reachable by other
651 * roots, and we don't use typed allocation in the other domains.
654 /* The sync block is no longer a GC pointer */
655 #define GC_HEADER_BITMAP (0)
657 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
659 static gsize*
660 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
662 MonoClassField *field;
663 MonoClass *p;
664 guint32 pos;
665 int max_size;
667 if (static_fields)
668 max_size = mono_class_data_size (class) / sizeof (gpointer);
669 else
670 max_size = class->instance_size / sizeof (gpointer);
671 if (max_size > size) {
672 g_assert (offset <= 0);
673 bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
674 size = max_size;
677 #ifdef HAVE_SGEN_GC
678 /*An Ephemeron cannot be marked by sgen*/
679 if (!static_fields && class->image == mono_defaults.corlib && !strcmp ("Ephemeron", class->name)) {
680 *max_set = 0;
681 memset (bitmap, 0, size / 8);
682 return bitmap;
684 #endif
686 for (p = class; p != NULL; p = p->parent) {
687 gpointer iter = NULL;
688 while ((field = mono_class_get_fields (p, &iter))) {
689 MonoType *type;
691 if (static_fields) {
692 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
693 continue;
694 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
695 continue;
696 } else {
697 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
698 continue;
700 /* FIXME: should not happen, flag as type load error */
701 if (field->type->byref)
702 break;
704 if (static_fields && field->offset == -1)
705 /* special static */
706 continue;
708 pos = field->offset / sizeof (gpointer);
709 pos += offset;
711 type = mono_type_get_underlying_type (field->type);
712 switch (type->type) {
713 case MONO_TYPE_I:
714 case MONO_TYPE_PTR:
715 case MONO_TYPE_FNPTR:
716 break;
717 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
718 case MONO_TYPE_U:
719 #ifdef HAVE_SGEN_GC
720 break;
721 #else
722 if (class->image != mono_defaults.corlib)
723 break;
724 #endif
725 case MONO_TYPE_STRING:
726 case MONO_TYPE_SZARRAY:
727 case MONO_TYPE_CLASS:
728 case MONO_TYPE_OBJECT:
729 case MONO_TYPE_ARRAY:
730 g_assert ((field->offset % sizeof(gpointer)) == 0);
732 g_assert (pos < size || pos <= max_size);
733 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
734 *max_set = MAX (*max_set, pos);
735 break;
736 case MONO_TYPE_GENERICINST:
737 if (!mono_type_generic_inst_is_valuetype (type)) {
738 g_assert ((field->offset % sizeof(gpointer)) == 0);
740 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
741 *max_set = MAX (*max_set, pos);
742 break;
743 } else {
744 /* fall through */
746 case MONO_TYPE_VALUETYPE: {
747 MonoClass *fclass = mono_class_from_mono_type (field->type);
748 if (fclass->has_references) {
749 /* remove the object header */
750 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
752 break;
754 case MONO_TYPE_I1:
755 case MONO_TYPE_U1:
756 case MONO_TYPE_I2:
757 case MONO_TYPE_U2:
758 case MONO_TYPE_I4:
759 case MONO_TYPE_U4:
760 case MONO_TYPE_I8:
761 case MONO_TYPE_U8:
762 case MONO_TYPE_R4:
763 case MONO_TYPE_R8:
764 case MONO_TYPE_BOOLEAN:
765 case MONO_TYPE_CHAR:
766 break;
767 default:
768 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
769 break;
772 if (static_fields)
773 break;
775 return bitmap;
779 * mono_class_compute_bitmap:
781 * Mono internal function to compute a bitmap of reference fields in a class.
783 gsize*
784 mono_class_compute_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
786 return compute_class_bitmap (class, bitmap, size, offset, max_set, static_fields);
789 #if 0
791 * similar to the above, but sets the bits in the bitmap for any non-ref field
792 * and ignores static fields
794 static gsize*
795 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
797 MonoClassField *field;
798 MonoClass *p;
799 guint32 pos, pos2;
800 int max_size;
802 max_size = class->instance_size / sizeof (gpointer);
803 if (max_size >= size) {
804 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
807 for (p = class; p != NULL; p = p->parent) {
808 gpointer iter = NULL;
809 while ((field = mono_class_get_fields (p, &iter))) {
810 MonoType *type;
812 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
813 continue;
814 /* FIXME: should not happen, flag as type load error */
815 if (field->type->byref)
816 break;
818 pos = field->offset / sizeof (gpointer);
819 pos += offset;
821 type = mono_type_get_underlying_type (field->type);
822 switch (type->type) {
823 #if SIZEOF_VOID_P == 8
824 case MONO_TYPE_I:
825 case MONO_TYPE_U:
826 case MONO_TYPE_PTR:
827 case MONO_TYPE_FNPTR:
828 #endif
829 case MONO_TYPE_I8:
830 case MONO_TYPE_U8:
831 case MONO_TYPE_R8:
832 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
833 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
834 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
836 /* fall through */
837 #if SIZEOF_VOID_P == 4
838 case MONO_TYPE_I:
839 case MONO_TYPE_U:
840 case MONO_TYPE_PTR:
841 case MONO_TYPE_FNPTR:
842 #endif
843 case MONO_TYPE_I4:
844 case MONO_TYPE_U4:
845 case MONO_TYPE_R4:
846 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
847 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
848 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
850 /* fall through */
851 case MONO_TYPE_CHAR:
852 case MONO_TYPE_I2:
853 case MONO_TYPE_U2:
854 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
855 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
856 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
858 /* fall through */
859 case MONO_TYPE_BOOLEAN:
860 case MONO_TYPE_I1:
861 case MONO_TYPE_U1:
862 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
863 break;
864 case MONO_TYPE_STRING:
865 case MONO_TYPE_SZARRAY:
866 case MONO_TYPE_CLASS:
867 case MONO_TYPE_OBJECT:
868 case MONO_TYPE_ARRAY:
869 break;
870 case MONO_TYPE_GENERICINST:
871 if (!mono_type_generic_inst_is_valuetype (type)) {
872 break;
873 } else {
874 /* fall through */
876 case MONO_TYPE_VALUETYPE: {
877 MonoClass *fclass = mono_class_from_mono_type (field->type);
878 /* remove the object header */
879 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
880 break;
882 default:
883 g_assert_not_reached ();
884 break;
888 return bitmap;
892 * mono_class_insecure_overlapping:
893 * check if a class with explicit layout has references and non-references
894 * fields overlapping.
896 * Returns: TRUE if it is insecure to load the type.
898 gboolean
899 mono_class_insecure_overlapping (MonoClass *klass)
901 int max_set = 0;
902 gsize *bitmap;
903 gsize default_bitmap [4] = {0};
904 gsize *nrbitmap;
905 gsize default_nrbitmap [4] = {0};
906 int i, insecure = FALSE;
907 return FALSE;
909 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
910 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
912 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
913 int idx = i % (sizeof (bitmap [0]) * 8);
914 if (bitmap [idx] & nrbitmap [idx]) {
915 insecure = TRUE;
916 break;
919 if (bitmap != default_bitmap)
920 g_free (bitmap);
921 if (nrbitmap != default_nrbitmap)
922 g_free (nrbitmap);
923 if (insecure) {
924 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
925 return FALSE;
927 return insecure;
929 #endif
931 MonoString*
932 mono_string_alloc (int length)
934 return mono_string_new_size (mono_domain_get (), length);
937 void
938 mono_class_compute_gc_descriptor (MonoClass *class)
940 int max_set = 0;
941 gsize *bitmap;
942 gsize default_bitmap [4] = {0};
943 static gboolean gcj_inited = FALSE;
945 if (!gcj_inited) {
946 mono_loader_lock ();
948 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
949 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
950 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
951 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
953 #ifdef HAVE_GC_GCJ_MALLOC
955 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
956 * turned on.
958 #if 0
959 #ifdef GC_REDIRECT_TO_LOCAL
960 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
961 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
962 #endif
963 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
964 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
965 #endif
967 #endif
968 gcj_inited = TRUE;
969 mono_loader_unlock ();
972 if (!class->inited)
973 mono_class_init (class);
975 if (class->gc_descr_inited)
976 return;
978 class->gc_descr_inited = TRUE;
979 class->gc_descr = GC_NO_DESCRIPTOR;
981 bitmap = default_bitmap;
982 if (class == mono_defaults.string_class) {
983 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
984 } else if (class->rank) {
985 mono_class_compute_gc_descriptor (class->element_class);
986 if (MONO_TYPE_IS_REFERENCE (&class->element_class->byval_arg)) {
987 gsize abm = 1;
988 class->gc_descr = mono_gc_make_descr_for_array (class->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
989 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
990 class->name_space, class->name);*/
991 } else {
992 /* remove the object header */
993 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
994 class->gc_descr = mono_gc_make_descr_for_array (class->byval_arg.type == MONO_TYPE_SZARRAY, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
995 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
996 class->name_space, class->name);*/
997 if (bitmap != default_bitmap)
998 g_free (bitmap);
1000 } else {
1001 /*static int count = 0;
1002 if (count++ > 58)
1003 return;*/
1004 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1005 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
1007 if (class->gc_descr == GC_NO_DESCRIPTOR)
1008 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1010 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1011 if (bitmap != default_bitmap)
1012 g_free (bitmap);
1017 * field_is_special_static:
1018 * @fklass: The MonoClass to look up.
1019 * @field: The MonoClassField describing the field.
1021 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1022 * SPECIAL_STATIC_NONE otherwise.
1024 static gint32
1025 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1027 MonoCustomAttrInfo *ainfo;
1028 int i;
1029 ainfo = mono_custom_attrs_from_field (fklass, field);
1030 if (!ainfo)
1031 return FALSE;
1032 for (i = 0; i < ainfo->num_attrs; ++i) {
1033 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1034 if (klass->image == mono_defaults.corlib) {
1035 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1036 mono_custom_attrs_free (ainfo);
1037 return SPECIAL_STATIC_THREAD;
1039 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1040 mono_custom_attrs_free (ainfo);
1041 return SPECIAL_STATIC_CONTEXT;
1045 mono_custom_attrs_free (ainfo);
1046 return SPECIAL_STATIC_NONE;
1049 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1050 #define mix(a,b,c) { \
1051 a -= c; a ^= rot(c, 4); c += b; \
1052 b -= a; b ^= rot(a, 6); a += c; \
1053 c -= b; c ^= rot(b, 8); b += a; \
1054 a -= c; a ^= rot(c,16); c += b; \
1055 b -= a; b ^= rot(a,19); a += c; \
1056 c -= b; c ^= rot(b, 4); b += a; \
1058 #define final(a,b,c) { \
1059 c ^= b; c -= rot(b,14); \
1060 a ^= c; a -= rot(c,11); \
1061 b ^= a; b -= rot(a,25); \
1062 c ^= b; c -= rot(b,16); \
1063 a ^= c; a -= rot(c,4); \
1064 b ^= a; b -= rot(a,14); \
1065 c ^= b; c -= rot(b,24); \
1069 * mono_method_get_imt_slot:
1071 * The IMT slot is embedded into AOTed code, so this must return the same value
1072 * for the same method across all executions. This means:
1073 * - pointers shouldn't be used as hash values.
1074 * - mono_metadata_str_hash () should be used for hashing strings.
1076 guint32
1077 mono_method_get_imt_slot (MonoMethod *method)
1079 MonoMethodSignature *sig;
1080 int hashes_count;
1081 guint32 *hashes_start, *hashes;
1082 guint32 a, b, c;
1083 int i;
1085 /* This can be used to stress tests the collision code */
1086 //return 0;
1089 * We do this to simplify generic sharing. It will hurt
1090 * performance in cases where a class implements two different
1091 * instantiations of the same generic interface.
1092 * The code in build_imt_slots () depends on this.
1094 if (method->is_inflated)
1095 method = ((MonoMethodInflated*)method)->declaring;
1097 sig = mono_method_signature (method);
1098 hashes_count = sig->param_count + 4;
1099 hashes_start = malloc (hashes_count * sizeof (guint32));
1100 hashes = hashes_start;
1102 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1103 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1104 method->klass->name_space, method->klass->name, method->name);
1107 /* Initialize hashes */
1108 hashes [0] = mono_metadata_str_hash (method->klass->name);
1109 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1110 hashes [2] = mono_metadata_str_hash (method->name);
1111 hashes [3] = mono_metadata_type_hash (sig->ret);
1112 for (i = 0; i < sig->param_count; i++) {
1113 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1116 /* Setup internal state */
1117 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1119 /* Handle most of the hashes */
1120 while (hashes_count > 3) {
1121 a += hashes [0];
1122 b += hashes [1];
1123 c += hashes [2];
1124 mix (a,b,c);
1125 hashes_count -= 3;
1126 hashes += 3;
1129 /* Handle the last 3 hashes (all the case statements fall through) */
1130 switch (hashes_count) {
1131 case 3 : c += hashes [2];
1132 case 2 : b += hashes [1];
1133 case 1 : a += hashes [0];
1134 final (a,b,c);
1135 case 0: /* nothing left to add */
1136 break;
1139 free (hashes_start);
1140 /* Report the result */
1141 return c % MONO_IMT_SIZE;
1143 #undef rot
1144 #undef mix
1145 #undef final
1147 #define DEBUG_IMT 0
1149 static void
1150 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1151 guint32 imt_slot = mono_method_get_imt_slot (method);
1152 MonoImtBuilderEntry *entry;
1154 if (slot_num >= 0 && imt_slot != slot_num) {
1155 /* we build just a single imt slot and this is not it */
1156 return;
1159 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1160 entry->key = method;
1161 entry->value.vtable_slot = vtable_slot;
1162 entry->next = imt_builder [imt_slot];
1163 if (imt_builder [imt_slot] != NULL) {
1164 entry->children = imt_builder [imt_slot]->children + 1;
1165 if (entry->children == 1) {
1166 mono_stats.imt_slots_with_collisions++;
1167 *imt_collisions_bitmap |= (1 << imt_slot);
1169 } else {
1170 entry->children = 0;
1171 mono_stats.imt_used_slots++;
1173 imt_builder [imt_slot] = entry;
1174 #if DEBUG_IMT
1176 char *method_name = mono_method_full_name (method, TRUE);
1177 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1178 method, method_name, imt_slot, vtable_slot, entry->children);
1179 g_free (method_name);
1181 #endif
1184 #if DEBUG_IMT
1185 static void
1186 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1187 if (e != NULL) {
1188 MonoMethod *method = e->key;
1189 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1190 message,
1191 num,
1192 method,
1193 method->klass->name_space,
1194 method->klass->name,
1195 method->name);
1196 } else {
1197 printf (" * %s: NULL\n", message);
1200 #endif
1202 static int
1203 compare_imt_builder_entries (const void *p1, const void *p2) {
1204 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1205 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1207 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1210 static int
1211 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1213 int count = end - start;
1214 int chunk_start = out_array->len;
1215 if (count < 4) {
1216 int i;
1217 for (i = start; i < end; ++i) {
1218 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1219 item->key = sorted_array [i]->key;
1220 item->value = sorted_array [i]->value;
1221 item->has_target_code = sorted_array [i]->has_target_code;
1222 item->is_equals = TRUE;
1223 if (i < end - 1)
1224 item->check_target_idx = out_array->len + 1;
1225 else
1226 item->check_target_idx = 0;
1227 g_ptr_array_add (out_array, item);
1229 } else {
1230 int middle = start + count / 2;
1231 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1233 item->key = sorted_array [middle]->key;
1234 item->is_equals = FALSE;
1235 g_ptr_array_add (out_array, item);
1236 imt_emit_ir (sorted_array, start, middle, out_array);
1237 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1239 return chunk_start;
1242 static GPtrArray*
1243 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1244 int number_of_entries = entries->children + 1;
1245 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1246 GPtrArray *result = g_ptr_array_new ();
1247 MonoImtBuilderEntry *current_entry;
1248 int i;
1250 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1251 sorted_array [i] = current_entry;
1253 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1255 /*for (i = 0; i < number_of_entries; i++) {
1256 print_imt_entry (" sorted array:", sorted_array [i], i);
1259 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1261 free (sorted_array);
1262 return result;
1265 static gpointer
1266 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1268 if (imt_builder_entry != NULL) {
1269 if (imt_builder_entry->children == 0 && !fail_tramp) {
1270 /* No collision, return the vtable slot contents */
1271 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1272 } else {
1273 /* Collision, build the thunk */
1274 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1275 gpointer result;
1276 int i;
1277 result = imt_thunk_builder (vtable, domain,
1278 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1279 for (i = 0; i < imt_ir->len; ++i)
1280 g_free (g_ptr_array_index (imt_ir, i));
1281 g_ptr_array_free (imt_ir, TRUE);
1282 return result;
1284 } else {
1285 if (fail_tramp)
1286 return fail_tramp;
1287 else
1288 /* Empty slot */
1289 return NULL;
1293 static MonoImtBuilderEntry*
1294 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1297 * LOCKING: requires the loader and domain locks.
1300 static void
1301 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1303 int i;
1304 GSList *list_item;
1305 guint32 imt_collisions_bitmap = 0;
1306 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1307 int method_count = 0;
1308 gboolean record_method_count_for_max_collisions = FALSE;
1309 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1311 #if DEBUG_IMT
1312 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1313 #endif
1314 for (i = 0; i < klass->interface_offsets_count; ++i) {
1315 MonoClass *iface = klass->interfaces_packed [i];
1316 int interface_offset = klass->interface_offsets_packed [i];
1317 int method_slot_in_interface, vt_slot;
1319 if (mono_class_has_variant_generic_params (iface))
1320 has_variant_iface = TRUE;
1322 mono_class_setup_methods (iface);
1323 vt_slot = interface_offset;
1324 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1325 MonoMethod *method;
1327 if (slot_num >= 0 && iface->is_inflated) {
1329 * The imt slot of the method is the same as for its declaring method,
1330 * see the comment in mono_method_get_imt_slot (), so we can
1331 * avoid inflating methods which will be discarded by
1332 * add_imt_builder_entry anyway.
1334 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1335 if (mono_method_get_imt_slot (method) != slot_num) {
1336 vt_slot ++;
1337 continue;
1340 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1341 if (method->is_generic) {
1342 has_generic_virtual = TRUE;
1343 vt_slot ++;
1344 continue;
1347 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1348 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1349 vt_slot ++;
1353 if (extra_interfaces) {
1354 int interface_offset = klass->vtable_size;
1356 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1357 MonoClass* iface = list_item->data;
1358 int method_slot_in_interface;
1359 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1360 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1362 if (method->is_generic)
1363 has_generic_virtual = TRUE;
1364 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1366 interface_offset += iface->method.count;
1369 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1370 /* overwrite the imt slot only if we're building all the entries or if
1371 * we're building this specific one
1373 if (slot_num < 0 || i == slot_num) {
1374 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1376 if (entries) {
1377 if (imt_builder [i]) {
1378 MonoImtBuilderEntry *entry;
1380 /* Link entries with imt_builder [i] */
1381 for (entry = entries; entry->next; entry = entry->next) {
1382 #if DEBUG_IMT
1383 MonoMethod *method = (MonoMethod*)entry->key;
1384 char *method_name = mono_method_full_name (method, TRUE);
1385 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1386 g_free (method_name);
1387 #endif
1389 entry->next = imt_builder [i];
1390 entries->children += imt_builder [i]->children + 1;
1392 imt_builder [i] = entries;
1395 if (has_generic_virtual || has_variant_iface) {
1397 * There might be collisions later when the the thunk is expanded.
1399 imt_collisions_bitmap |= (1 << i);
1402 * The IMT thunk might be called with an instance of one of the
1403 * generic virtual methods, so has to fallback to the IMT trampoline.
1405 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline ? callbacks.get_imt_trampoline (i) : NULL);
1406 } else {
1407 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1409 #if DEBUG_IMT
1410 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1411 #endif
1414 if (imt_builder [i] != NULL) {
1415 int methods_in_slot = imt_builder [i]->children + 1;
1416 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1417 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1418 record_method_count_for_max_collisions = TRUE;
1420 method_count += methods_in_slot;
1424 mono_stats.imt_number_of_methods += method_count;
1425 if (record_method_count_for_max_collisions) {
1426 mono_stats.imt_method_count_when_max_collisions = method_count;
1429 for (i = 0; i < MONO_IMT_SIZE; i++) {
1430 MonoImtBuilderEntry* entry = imt_builder [i];
1431 while (entry != NULL) {
1432 MonoImtBuilderEntry* next = entry->next;
1433 g_free (entry);
1434 entry = next;
1437 free (imt_builder);
1438 /* we OR the bitmap since we may build just a single imt slot at a time */
1439 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1442 static void
1443 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1444 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1448 * mono_vtable_build_imt_slot:
1449 * @vtable: virtual object table struct
1450 * @imt_slot: slot in the IMT table
1452 * Fill the given @imt_slot in the IMT table of @vtable with
1453 * a trampoline or a thunk for the case of collisions.
1454 * This is part of the internal mono API.
1456 * LOCKING: Take the domain lock.
1458 void
1459 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1461 gpointer *imt = (gpointer*)vtable;
1462 imt -= MONO_IMT_SIZE;
1463 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1465 /* no support for extra interfaces: the proxy objects will need
1466 * to build the complete IMT
1467 * Update and heck needs to ahppen inside the proper domain lock, as all
1468 * the changes made to a MonoVTable.
1470 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1471 mono_domain_lock (vtable->domain);
1472 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1473 if (imt [imt_slot] == callbacks.get_imt_trampoline (imt_slot))
1474 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1475 mono_domain_unlock (vtable->domain);
1476 mono_loader_unlock ();
1481 * The first two free list entries both belong to the wait list: The
1482 * first entry is the pointer to the head of the list and the second
1483 * entry points to the last element. That way appending and removing
1484 * the first element are both O(1) operations.
1486 #ifdef MONO_SMALL_CONFIG
1487 #define NUM_FREE_LISTS 6
1488 #else
1489 #define NUM_FREE_LISTS 12
1490 #endif
1491 #define FIRST_FREE_LIST_SIZE 64
1492 #define MAX_WAIT_LENGTH 50
1493 #define THUNK_THRESHOLD 10
1496 * LOCKING: The domain lock must be held.
1498 static void
1499 init_thunk_free_lists (MonoDomain *domain)
1501 if (domain->thunk_free_lists)
1502 return;
1503 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1506 static int
1507 list_index_for_size (int item_size)
1509 int i = 2;
1510 int size = FIRST_FREE_LIST_SIZE;
1512 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1513 i++;
1514 size <<= 1;
1517 return i;
1521 * mono_method_alloc_generic_virtual_thunk:
1522 * @domain: a domain
1523 * @size: size in bytes
1525 * Allocs size bytes to be used for the code of a generic virtual
1526 * thunk. It's either allocated from the domain's code manager or
1527 * reused from a previously invalidated piece.
1529 * LOCKING: The domain lock must be held.
1531 gpointer
1532 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1534 static gboolean inited = FALSE;
1535 static int generic_virtual_thunks_size = 0;
1537 guint32 *p;
1538 int i;
1539 MonoThunkFreeList **l;
1541 init_thunk_free_lists (domain);
1543 size += sizeof (guint32);
1544 if (size < sizeof (MonoThunkFreeList))
1545 size = sizeof (MonoThunkFreeList);
1547 i = list_index_for_size (size);
1548 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1549 if ((*l)->size >= size) {
1550 MonoThunkFreeList *item = *l;
1551 *l = item->next;
1552 return ((guint32*)item) + 1;
1556 /* no suitable item found - search lists of larger sizes */
1557 while (++i < NUM_FREE_LISTS) {
1558 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1559 if (!item)
1560 continue;
1561 g_assert (item->size > size);
1562 domain->thunk_free_lists [i] = item->next;
1563 return ((guint32*)item) + 1;
1566 /* still nothing found - allocate it */
1567 if (!inited) {
1568 mono_counters_register ("Generic virtual thunk bytes",
1569 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1570 inited = TRUE;
1572 generic_virtual_thunks_size += size;
1574 p = mono_domain_code_reserve (domain, size);
1575 *p = size;
1577 mono_domain_lock (domain);
1578 if (!domain->generic_virtual_thunks)
1579 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1580 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1581 mono_domain_unlock (domain);
1583 return p + 1;
1587 * LOCKING: The domain lock must be held.
1589 static void
1590 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1592 guint32 *p = code;
1593 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1594 gboolean found = FALSE;
1596 mono_domain_lock (domain);
1597 if (!domain->generic_virtual_thunks)
1598 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1599 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1600 found = TRUE;
1601 mono_domain_unlock (domain);
1603 if (!found)
1604 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1605 return;
1606 init_thunk_free_lists (domain);
1608 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1609 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1610 int length = item->length;
1611 int i;
1613 /* unlink the first item from the wait list */
1614 domain->thunk_free_lists [0] = item->next;
1615 domain->thunk_free_lists [0]->length = length - 1;
1617 i = list_index_for_size (item->size);
1619 /* put it in the free list */
1620 item->next = domain->thunk_free_lists [i];
1621 domain->thunk_free_lists [i] = item;
1624 l->next = NULL;
1625 if (domain->thunk_free_lists [1]) {
1626 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1627 domain->thunk_free_lists [0]->length++;
1628 } else {
1629 g_assert (!domain->thunk_free_lists [0]);
1631 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1632 domain->thunk_free_lists [0]->length = 1;
1636 typedef struct _GenericVirtualCase {
1637 MonoMethod *method;
1638 gpointer code;
1639 int count;
1640 struct _GenericVirtualCase *next;
1641 } GenericVirtualCase;
1644 * get_generic_virtual_entries:
1646 * Return IMT entries for the generic virtual method instances and
1647 * variant interface methods for vtable slot
1648 * VTABLE_SLOT.
1650 static MonoImtBuilderEntry*
1651 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1653 GenericVirtualCase *list;
1654 MonoImtBuilderEntry *entries;
1656 mono_domain_lock (domain);
1657 if (!domain->generic_virtual_cases)
1658 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1660 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1662 entries = NULL;
1663 for (; list; list = list->next) {
1664 MonoImtBuilderEntry *entry;
1666 if (list->count < THUNK_THRESHOLD)
1667 continue;
1669 entry = g_new0 (MonoImtBuilderEntry, 1);
1670 entry->key = list->method;
1671 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1672 entry->has_target_code = 1;
1673 if (entries)
1674 entry->children = entries->children + 1;
1675 entry->next = entries;
1676 entries = entry;
1679 mono_domain_unlock (domain);
1681 /* FIXME: Leaking memory ? */
1682 return entries;
1686 * mono_method_add_generic_virtual_invocation:
1687 * @domain: a domain
1688 * @vtable_slot: pointer to the vtable slot
1689 * @method: the inflated generic virtual method
1690 * @code: the method's code
1692 * Registers a call via unmanaged code to a generic virtual method
1693 * instantiation or variant interface method. If the number of calls reaches a threshold
1694 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1695 * virtual method thunk.
1697 void
1698 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1699 gpointer *vtable_slot,
1700 MonoMethod *method, gpointer code)
1702 static gboolean inited = FALSE;
1703 static int num_added = 0;
1705 GenericVirtualCase *gvc, *list;
1706 MonoImtBuilderEntry *entries;
1707 int i;
1708 GPtrArray *sorted;
1710 mono_domain_lock (domain);
1711 if (!domain->generic_virtual_cases)
1712 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1714 /* Check whether the case was already added */
1715 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1716 gvc = list;
1717 while (gvc) {
1718 if (gvc->method == method)
1719 break;
1720 gvc = gvc->next;
1723 /* If not found, make a new one */
1724 if (!gvc) {
1725 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1726 gvc->method = method;
1727 gvc->code = code;
1728 gvc->count = 0;
1729 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1731 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1733 if (!inited) {
1734 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1735 inited = TRUE;
1737 num_added++;
1740 if (++gvc->count == THUNK_THRESHOLD) {
1741 gpointer *old_thunk = *vtable_slot;
1742 gpointer vtable_trampoline = NULL;
1743 gpointer imt_trampoline = NULL;
1745 if ((gpointer)vtable_slot < (gpointer)vtable) {
1746 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1747 int imt_slot = MONO_IMT_SIZE + displacement;
1749 /* Force the rebuild of the thunk at the next call */
1750 imt_trampoline = callbacks.get_imt_trampoline (imt_slot);
1751 *vtable_slot = imt_trampoline;
1752 } else {
1753 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1755 entries = get_generic_virtual_entries (domain, vtable_slot);
1757 sorted = imt_sort_slot_entries (entries);
1759 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1760 vtable_trampoline);
1762 while (entries) {
1763 MonoImtBuilderEntry *next = entries->next;
1764 g_free (entries);
1765 entries = next;
1768 for (i = 0; i < sorted->len; ++i)
1769 g_free (g_ptr_array_index (sorted, i));
1770 g_ptr_array_free (sorted, TRUE);
1773 #ifndef __native_client__
1774 /* We don't re-use any thunks as there is a lot of overhead */
1775 /* to deleting and re-using code in Native Client. */
1776 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1777 invalidate_generic_virtual_thunk (domain, old_thunk);
1778 #endif
1781 mono_domain_unlock (domain);
1784 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1787 * mono_class_vtable:
1788 * @domain: the application domain
1789 * @class: the class to initialize
1791 * VTables are domain specific because we create domain specific code, and
1792 * they contain the domain specific static class data.
1793 * On failure, NULL is returned, and class->exception_type is set.
1795 MonoVTable *
1796 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1798 return mono_class_vtable_full (domain, class, FALSE);
1802 * mono_class_vtable_full:
1803 * @domain: the application domain
1804 * @class: the class to initialize
1805 * @raise_on_error if an exception should be raised on failure or not
1807 * VTables are domain specific because we create domain specific code, and
1808 * they contain the domain specific static class data.
1810 MonoVTable *
1811 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1813 MonoClassRuntimeInfo *runtime_info;
1815 g_assert (class);
1817 if (class->exception_type) {
1818 if (raise_on_error)
1819 mono_raise_exception (mono_class_get_exception_for_failure (class));
1820 return NULL;
1823 /* this check can be inlined in jitted code, too */
1824 runtime_info = class->runtime_info;
1825 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1826 return runtime_info->domain_vtables [domain->domain_id];
1827 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1831 * mono_class_try_get_vtable:
1832 * @domain: the application domain
1833 * @class: the class to initialize
1835 * This function tries to get the associated vtable from @class if
1836 * it was already created.
1838 MonoVTable *
1839 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1841 MonoClassRuntimeInfo *runtime_info;
1843 g_assert (class);
1845 runtime_info = class->runtime_info;
1846 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1847 return runtime_info->domain_vtables [domain->domain_id];
1848 return NULL;
1851 static gpointer*
1852 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1854 size_t alloc_offset;
1857 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1858 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1859 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1861 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1862 g_assert ((imt_table_bytes & 7) == 4);
1863 vtable_size += 4;
1864 alloc_offset = 4;
1865 } else {
1866 alloc_offset = 0;
1869 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1872 static MonoVTable *
1873 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1875 MonoVTable *vt;
1876 MonoClassRuntimeInfo *runtime_info, *old_info;
1877 MonoClassField *field;
1878 char *t;
1879 int i, vtable_slots;
1880 size_t imt_table_bytes;
1881 int gc_bits;
1882 guint32 vtable_size, class_size;
1883 gpointer iter;
1884 gpointer *interface_offsets;
1886 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1887 mono_domain_lock (domain);
1888 runtime_info = class->runtime_info;
1889 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1890 mono_domain_unlock (domain);
1891 mono_loader_unlock ();
1892 return runtime_info->domain_vtables [domain->domain_id];
1894 if (!class->inited || class->exception_type) {
1895 if (!mono_class_init (class) || class->exception_type) {
1896 mono_domain_unlock (domain);
1897 mono_loader_unlock ();
1898 if (raise_on_error)
1899 mono_raise_exception (mono_class_get_exception_for_failure (class));
1900 return NULL;
1904 /* Array types require that their element type be valid*/
1905 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1906 MonoClass *element_class = class->element_class;
1907 if (!element_class->inited)
1908 mono_class_init (element_class);
1910 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1911 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1912 mono_class_setup_vtable (element_class);
1914 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1915 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1916 if (class->exception_type == MONO_EXCEPTION_NONE)
1917 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1918 mono_domain_unlock (domain);
1919 mono_loader_unlock ();
1920 if (raise_on_error)
1921 mono_raise_exception (mono_class_get_exception_for_failure (class));
1922 return NULL;
1927 * For some classes, mono_class_init () already computed class->vtable_size, and
1928 * that is all that is needed because of the vtable trampolines.
1930 if (!class->vtable_size)
1931 mono_class_setup_vtable (class);
1933 if (class->generic_class && !class->vtable)
1934 mono_class_check_vtable_constraints (class, NULL);
1936 /* Initialize klass->has_finalize */
1937 mono_class_has_finalizer (class);
1939 if (class->exception_type) {
1940 mono_domain_unlock (domain);
1941 mono_loader_unlock ();
1942 if (raise_on_error)
1943 mono_raise_exception (mono_class_get_exception_for_failure (class));
1944 return NULL;
1947 vtable_slots = class->vtable_size;
1948 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1949 class_size = mono_class_data_size (class);
1950 if (class_size)
1951 vtable_slots++;
1953 if (ARCH_USE_IMT) {
1954 if (class->interface_offsets_count) {
1955 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1956 mono_stats.imt_number_of_tables++;
1957 mono_stats.imt_tables_size += imt_table_bytes;
1958 } else {
1959 imt_table_bytes = 0;
1961 } else {
1962 imt_table_bytes = sizeof (gpointer) * (class->max_interface_id + 1);
1965 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1967 mono_stats.used_class_count++;
1968 mono_stats.class_vtable_size += vtable_size;
1970 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1971 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1972 g_assert (!((gsize)vt & 7));
1974 vt->klass = class;
1975 vt->rank = class->rank;
1976 vt->domain = domain;
1978 mono_class_compute_gc_descriptor (class);
1980 * We can't use typed allocation in the non-root domains, since the
1981 * collector needs the GC descriptor stored in the vtable even after
1982 * the mempool containing the vtable is destroyed when the domain is
1983 * unloaded. An alternative might be to allocate vtables in the GC
1984 * heap, but this does not seem to work (it leads to crashes inside
1985 * libgc). If that approach is tried, two gc descriptors need to be
1986 * allocated for each class: one for the root domain, and one for all
1987 * other domains. The second descriptor should contain a bit for the
1988 * vtable field in MonoObject, since we can no longer assume the
1989 * vtable is reachable by other roots after the appdomain is unloaded.
1991 #ifdef HAVE_BOEHM_GC
1992 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1993 vt->gc_descr = GC_NO_DESCRIPTOR;
1994 else
1995 #endif
1996 vt->gc_descr = class->gc_descr;
1998 gc_bits = mono_gc_get_vtable_bits (class);
1999 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2001 vt->gc_bits = gc_bits;
2003 if (class_size) {
2004 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2005 if (class->has_static_refs) {
2006 gpointer statics_gc_descr;
2007 int max_set = 0;
2008 gsize default_bitmap [4] = {0};
2009 gsize *bitmap;
2011 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2012 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
2013 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2014 vt->vtable [class->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr);
2015 mono_domain_add_class_static_data (domain, class, vt->vtable [class->vtable_size], NULL);
2016 if (bitmap != default_bitmap)
2017 g_free (bitmap);
2018 } else {
2019 vt->vtable [class->vtable_size] = mono_domain_alloc0 (domain, class_size);
2021 vt->has_static_fields = TRUE;
2022 mono_stats.class_static_data_size += class_size;
2025 iter = NULL;
2026 while ((field = mono_class_get_fields (class, &iter))) {
2027 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2028 continue;
2029 if (mono_field_is_deleted (field))
2030 continue;
2031 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2032 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
2033 if (special_static != SPECIAL_STATIC_NONE) {
2034 guint32 size, offset;
2035 gint32 align;
2036 gsize default_bitmap [4] = {0};
2037 gsize *bitmap;
2038 int max_set = 0;
2039 int numbits;
2040 MonoClass *fclass;
2041 if (mono_type_is_reference (field->type)) {
2042 default_bitmap [0] = 1;
2043 numbits = 1;
2044 bitmap = default_bitmap;
2045 } else if (mono_type_is_struct (field->type)) {
2046 fclass = mono_class_from_mono_type (field->type);
2047 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2048 numbits = max_set + 1;
2049 } else {
2050 default_bitmap [0] = 0;
2051 numbits = 0;
2052 bitmap = default_bitmap;
2054 size = mono_type_size (field->type, &align);
2055 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2056 if (!domain->special_static_fields)
2057 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2058 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2059 if (bitmap != default_bitmap)
2060 g_free (bitmap);
2062 * This marks the field as special static to speed up the
2063 * checks in mono_field_static_get/set_value ().
2065 field->offset = -1;
2066 continue;
2069 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2070 MonoClass *fklass = mono_class_from_mono_type (field->type);
2071 const char *data = mono_field_get_data (field);
2073 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2074 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2075 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2076 if (!data)
2077 continue;
2078 if (fklass->valuetype) {
2079 memcpy (t, data, mono_class_value_size (fklass, NULL));
2080 } else {
2081 /* it's a pointer type: add check */
2082 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2083 *t = *(char *)data;
2085 continue;
2089 vt->max_interface_id = class->max_interface_id;
2090 vt->interface_bitmap = class->interface_bitmap;
2092 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2093 // class->name, class->interface_offsets_count);
2095 if (! ARCH_USE_IMT) {
2096 /* initialize interface offsets */
2097 for (i = 0; i < class->interface_offsets_count; ++i) {
2098 int interface_id = class->interfaces_packed [i]->interface_id;
2099 int slot = class->interface_offsets_packed [i];
2100 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
2104 /* Initialize vtable */
2105 if (callbacks.get_vtable_trampoline) {
2106 // This also covers the AOT case
2107 for (i = 0; i < class->vtable_size; ++i) {
2108 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2110 } else {
2111 mono_class_setup_vtable (class);
2113 for (i = 0; i < class->vtable_size; ++i) {
2114 MonoMethod *cm;
2116 if ((cm = class->vtable [i]))
2117 vt->vtable [i] = arch_create_jit_trampoline (cm);
2121 if (ARCH_USE_IMT && imt_table_bytes) {
2122 /* Now that the vtable is full, we can actually fill up the IMT */
2123 if (callbacks.get_imt_trampoline) {
2124 /* lazy construction of the IMT entries enabled */
2125 for (i = 0; i < MONO_IMT_SIZE; ++i)
2126 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2127 } else {
2128 build_imt (class, vt, domain, interface_offsets, NULL);
2133 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2134 * re-acquire them and check if another thread has created the vtable in the meantime.
2136 /* Special case System.MonoType to avoid infinite recursion */
2137 if (class != mono_defaults.monotype_class) {
2138 /*FIXME check for OOM*/
2139 vt->type = mono_type_get_object (domain, &class->byval_arg);
2140 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2141 /* This is unregistered in
2142 unregister_vtable_reflection_type() in
2143 domain.c. */
2144 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2147 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (class));
2149 /* class_vtable_array keeps an array of created vtables
2151 g_ptr_array_add (domain->class_vtable_array, vt);
2152 /* class->runtime_info is protected by the loader lock, both when
2153 * it it enlarged and when it is stored info.
2157 * Store the vtable in class->runtime_info.
2158 * class->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2160 mono_memory_barrier ();
2162 old_info = class->runtime_info;
2163 if (old_info && old_info->max_domain >= domain->domain_id) {
2164 /* someone already created a large enough runtime info */
2165 old_info->domain_vtables [domain->domain_id] = vt;
2166 } else {
2167 int new_size = domain->domain_id;
2168 if (old_info)
2169 new_size = MAX (new_size, old_info->max_domain);
2170 new_size++;
2171 /* make the new size a power of two */
2172 i = 2;
2173 while (new_size > i)
2174 i <<= 1;
2175 new_size = i;
2176 /* this is a bounded memory retention issue: may want to
2177 * handle it differently when we'll have a rcu-like system.
2179 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2180 runtime_info->max_domain = new_size - 1;
2181 /* copy the stuff from the older info */
2182 if (old_info) {
2183 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2185 runtime_info->domain_vtables [domain->domain_id] = vt;
2186 /* keep this last*/
2187 mono_memory_barrier ();
2188 class->runtime_info = runtime_info;
2191 if (class == mono_defaults.monotype_class) {
2192 /*FIXME check for OOM*/
2193 vt->type = mono_type_get_object (domain, &class->byval_arg);
2194 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2195 /* This is unregistered in
2196 unregister_vtable_reflection_type() in
2197 domain.c. */
2198 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2201 mono_domain_unlock (domain);
2202 mono_loader_unlock ();
2204 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2205 if (mono_security_enabled () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2206 mono_raise_exception (mono_class_get_exception_for_failure (class));
2208 /* make sure the parent is initialized */
2209 /*FIXME shouldn't this fail the current type?*/
2210 if (class->parent)
2211 mono_class_vtable_full (domain, class->parent, raise_on_error);
2213 return vt;
2216 #ifndef DISABLE_REMOTING
2218 * mono_class_proxy_vtable:
2219 * @domain: the application domain
2220 * @remove_class: the remote class
2222 * Creates a vtable for transparent proxies. It is basically
2223 * a copy of the real vtable of the class wrapped in @remote_class,
2224 * but all function pointers invoke the remoting functions, and
2225 * vtable->klass points to the transparent proxy class, and not to @class.
2227 static MonoVTable *
2228 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2230 MonoError error;
2231 MonoVTable *vt, *pvt;
2232 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2233 MonoClass *k;
2234 GSList *extra_interfaces = NULL;
2235 MonoClass *class = remote_class->proxy_class;
2236 gpointer *interface_offsets;
2237 uint8_t *bitmap;
2238 int bsize;
2239 size_t imt_table_bytes;
2241 #ifdef COMPRESSED_INTERFACE_BITMAP
2242 int bcsize;
2243 #endif
2245 vt = mono_class_vtable (domain, class);
2246 g_assert (vt); /*FIXME property handle failure*/
2247 max_interface_id = vt->max_interface_id;
2249 /* Calculate vtable space for extra interfaces */
2250 for (j = 0; j < remote_class->interface_count; j++) {
2251 MonoClass* iclass = remote_class->interfaces[j];
2252 GPtrArray *ifaces;
2253 int method_count;
2255 /*FIXME test for interfaces with variant generic arguments*/
2256 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2257 continue; /* interface implemented by the class */
2258 if (g_slist_find (extra_interfaces, iclass))
2259 continue;
2261 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2263 method_count = mono_class_num_methods (iclass);
2265 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2266 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2267 if (ifaces) {
2268 for (i = 0; i < ifaces->len; ++i) {
2269 MonoClass *ic = g_ptr_array_index (ifaces, i);
2270 /*FIXME test for interfaces with variant generic arguments*/
2271 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2272 continue; /* interface implemented by the class */
2273 if (g_slist_find (extra_interfaces, ic))
2274 continue;
2275 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2276 method_count += mono_class_num_methods (ic);
2278 g_ptr_array_free (ifaces, TRUE);
2281 extra_interface_vtsize += method_count * sizeof (gpointer);
2282 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2285 if (ARCH_USE_IMT) {
2286 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2287 mono_stats.imt_number_of_tables++;
2288 mono_stats.imt_tables_size += imt_table_bytes;
2289 } else {
2290 imt_table_bytes = sizeof (gpointer) * (max_interface_id + 1);
2293 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2295 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2297 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2298 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2299 g_assert (!((gsize)pvt & 7));
2301 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2303 pvt->klass = mono_defaults.transparent_proxy_class;
2304 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2305 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2307 /* initialize vtable */
2308 mono_class_setup_vtable (class);
2309 for (i = 0; i < class->vtable_size; ++i) {
2310 MonoMethod *cm;
2312 if ((cm = class->vtable [i]))
2313 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2314 else
2315 pvt->vtable [i] = NULL;
2318 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2319 /* create trampolines for abstract methods */
2320 for (k = class; k; k = k->parent) {
2321 MonoMethod* m;
2322 gpointer iter = NULL;
2323 while ((m = mono_class_get_methods (k, &iter)))
2324 if (!pvt->vtable [m->slot])
2325 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2329 pvt->max_interface_id = max_interface_id;
2330 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2331 #ifdef COMPRESSED_INTERFACE_BITMAP
2332 bitmap = g_malloc0 (bsize);
2333 #else
2334 bitmap = mono_domain_alloc0 (domain, bsize);
2335 #endif
2337 if (! ARCH_USE_IMT) {
2338 /* initialize interface offsets */
2339 for (i = 0; i < class->interface_offsets_count; ++i) {
2340 int interface_id = class->interfaces_packed [i]->interface_id;
2341 int slot = class->interface_offsets_packed [i];
2342 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2345 for (i = 0; i < class->interface_offsets_count; ++i) {
2346 int interface_id = class->interfaces_packed [i]->interface_id;
2347 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2350 if (extra_interfaces) {
2351 int slot = class->vtable_size;
2352 MonoClass* interf;
2353 gpointer iter;
2354 MonoMethod* cm;
2355 GSList *list_item;
2357 /* Create trampolines for the methods of the interfaces */
2358 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2359 interf = list_item->data;
2361 if (! ARCH_USE_IMT) {
2362 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2364 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2366 iter = NULL;
2367 j = 0;
2368 while ((cm = mono_class_get_methods (interf, &iter)))
2369 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2371 slot += mono_class_num_methods (interf);
2373 if (! ARCH_USE_IMT) {
2374 g_slist_free (extra_interfaces);
2378 if (ARCH_USE_IMT) {
2379 /* Now that the vtable is full, we can actually fill up the IMT */
2380 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2381 if (extra_interfaces) {
2382 g_slist_free (extra_interfaces);
2386 #ifdef COMPRESSED_INTERFACE_BITMAP
2387 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2388 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2389 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2390 g_free (bitmap);
2391 #else
2392 pvt->interface_bitmap = bitmap;
2393 #endif
2394 return pvt;
2397 #endif /* DISABLE_REMOTING */
2400 * mono_class_field_is_special_static:
2402 * Returns whether @field is a thread/context static field.
2404 gboolean
2405 mono_class_field_is_special_static (MonoClassField *field)
2407 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2408 return FALSE;
2409 if (mono_field_is_deleted (field))
2410 return FALSE;
2411 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2412 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2413 return TRUE;
2415 return FALSE;
2419 * mono_class_field_get_special_static_type:
2420 * @field: The MonoClassField describing the field.
2422 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2423 * SPECIAL_STATIC_NONE otherwise.
2425 guint32
2426 mono_class_field_get_special_static_type (MonoClassField *field)
2428 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2429 return SPECIAL_STATIC_NONE;
2430 if (mono_field_is_deleted (field))
2431 return SPECIAL_STATIC_NONE;
2432 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2433 return field_is_special_static (field->parent, field);
2434 return SPECIAL_STATIC_NONE;
2438 * mono_class_has_special_static_fields:
2440 * Returns whenever @klass has any thread/context static fields.
2442 gboolean
2443 mono_class_has_special_static_fields (MonoClass *klass)
2445 MonoClassField *field;
2446 gpointer iter;
2448 iter = NULL;
2449 while ((field = mono_class_get_fields (klass, &iter))) {
2450 g_assert (field->parent == klass);
2451 if (mono_class_field_is_special_static (field))
2452 return TRUE;
2455 return FALSE;
2458 #ifndef DISABLE_REMOTING
2460 * create_remote_class_key:
2461 * Creates an array of pointers that can be used as a hash key for a remote class.
2462 * The first element of the array is the number of pointers.
2464 static gpointer*
2465 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2467 gpointer *key;
2468 int i, j;
2470 if (remote_class == NULL) {
2471 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2472 key = g_malloc (sizeof(gpointer) * 3);
2473 key [0] = GINT_TO_POINTER (2);
2474 key [1] = mono_defaults.marshalbyrefobject_class;
2475 key [2] = extra_class;
2476 } else {
2477 key = g_malloc (sizeof(gpointer) * 2);
2478 key [0] = GINT_TO_POINTER (1);
2479 key [1] = extra_class;
2481 } else {
2482 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2483 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2484 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2485 key [1] = remote_class->proxy_class;
2487 // Keep the list of interfaces sorted
2488 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2489 if (extra_class && remote_class->interfaces [i] > extra_class) {
2490 key [j++] = extra_class;
2491 extra_class = NULL;
2493 key [j] = remote_class->interfaces [i];
2495 if (extra_class)
2496 key [j] = extra_class;
2497 } else {
2498 // Replace the old class. The interface list is the same
2499 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2500 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2501 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2502 for (i = 0; i < remote_class->interface_count; i++)
2503 key [2 + i] = remote_class->interfaces [i];
2507 return key;
2511 * copy_remote_class_key:
2513 * Make a copy of KEY in the domain and return the copy.
2515 static gpointer*
2516 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2518 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2519 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2521 memcpy (mp_key, key, key_size);
2523 return mp_key;
2527 * mono_remote_class:
2528 * @domain: the application domain
2529 * @class_name: name of the remote class
2531 * Creates and initializes a MonoRemoteClass object for a remote type.
2533 * Can raise an exception on failure.
2535 MonoRemoteClass*
2536 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2538 MonoError error;
2539 MonoRemoteClass *rc;
2540 gpointer* key, *mp_key;
2541 char *name;
2543 key = create_remote_class_key (NULL, proxy_class);
2545 mono_domain_lock (domain);
2546 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2548 if (rc) {
2549 g_free (key);
2550 mono_domain_unlock (domain);
2551 return rc;
2554 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2555 if (!mono_error_ok (&error)) {
2556 g_free (key);
2557 mono_domain_unlock (domain);
2558 mono_error_raise_exception (&error);
2561 mp_key = copy_remote_class_key (domain, key);
2562 g_free (key);
2563 key = mp_key;
2565 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2566 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2567 rc->interface_count = 1;
2568 rc->interfaces [0] = proxy_class;
2569 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2570 } else {
2571 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2572 rc->interface_count = 0;
2573 rc->proxy_class = proxy_class;
2576 rc->default_vtable = NULL;
2577 rc->xdomain_vtable = NULL;
2578 rc->proxy_class_name = name;
2579 #ifndef DISABLE_PERFCOUNTERS
2580 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2581 #endif
2583 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2585 mono_domain_unlock (domain);
2586 return rc;
2590 * clone_remote_class:
2591 * Creates a copy of the remote_class, adding the provided class or interface
2593 static MonoRemoteClass*
2594 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2596 MonoRemoteClass *rc;
2597 gpointer* key, *mp_key;
2599 key = create_remote_class_key (remote_class, extra_class);
2600 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2601 if (rc != NULL) {
2602 g_free (key);
2603 return rc;
2606 mp_key = copy_remote_class_key (domain, key);
2607 g_free (key);
2608 key = mp_key;
2610 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2611 int i,j;
2612 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2613 rc->proxy_class = remote_class->proxy_class;
2614 rc->interface_count = remote_class->interface_count + 1;
2616 // Keep the list of interfaces sorted, since the hash key of
2617 // the remote class depends on this
2618 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2619 if (remote_class->interfaces [i] > extra_class && i == j)
2620 rc->interfaces [j++] = extra_class;
2621 rc->interfaces [j] = remote_class->interfaces [i];
2623 if (i == j)
2624 rc->interfaces [j] = extra_class;
2625 } else {
2626 // Replace the old class. The interface array is the same
2627 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2628 rc->proxy_class = extra_class;
2629 rc->interface_count = remote_class->interface_count;
2630 if (rc->interface_count > 0)
2631 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2634 rc->default_vtable = NULL;
2635 rc->xdomain_vtable = NULL;
2636 rc->proxy_class_name = remote_class->proxy_class_name;
2638 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2640 return rc;
2643 gpointer
2644 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2646 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2647 mono_domain_lock (domain);
2648 if (rp->target_domain_id != -1) {
2649 if (remote_class->xdomain_vtable == NULL)
2650 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2651 mono_domain_unlock (domain);
2652 mono_loader_unlock ();
2653 return remote_class->xdomain_vtable;
2655 if (remote_class->default_vtable == NULL) {
2656 MonoType *type;
2657 MonoClass *klass;
2658 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2659 klass = mono_class_from_mono_type (type);
2660 #ifndef DISABLE_COM
2661 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)))
2662 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2663 else
2664 #endif
2665 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2668 mono_domain_unlock (domain);
2669 mono_loader_unlock ();
2670 return remote_class->default_vtable;
2674 * mono_upgrade_remote_class:
2675 * @domain: the application domain
2676 * @tproxy: the proxy whose remote class has to be upgraded.
2677 * @klass: class to which the remote class can be casted.
2679 * Updates the vtable of the remote class by adding the necessary method slots
2680 * and interface offsets so it can be safely casted to klass. klass can be a
2681 * class or an interface.
2683 void
2684 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2686 MonoTransparentProxy *tproxy;
2687 MonoRemoteClass *remote_class;
2688 gboolean redo_vtable;
2690 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2691 mono_domain_lock (domain);
2693 tproxy = (MonoTransparentProxy*) proxy_object;
2694 remote_class = tproxy->remote_class;
2696 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2697 int i;
2698 redo_vtable = TRUE;
2699 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2700 if (remote_class->interfaces [i] == klass)
2701 redo_vtable = FALSE;
2703 else {
2704 redo_vtable = (remote_class->proxy_class != klass);
2707 if (redo_vtable) {
2708 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2709 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2712 mono_domain_unlock (domain);
2713 mono_loader_unlock ();
2715 #endif /* DISABLE_REMOTING */
2719 * mono_object_get_virtual_method:
2720 * @obj: object to operate on.
2721 * @method: method
2723 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2724 * the instance of a callvirt of method.
2726 MonoMethod*
2727 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2729 MonoClass *klass;
2730 MonoMethod **vtable;
2731 gboolean is_proxy = FALSE;
2732 MonoMethod *res = NULL;
2734 klass = mono_object_class (obj);
2735 #ifndef DISABLE_REMOTING
2736 if (klass == mono_defaults.transparent_proxy_class) {
2737 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2738 is_proxy = TRUE;
2740 #endif
2742 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2743 return method;
2745 mono_class_setup_vtable (klass);
2746 vtable = klass->vtable;
2748 if (method->slot == -1) {
2749 /* method->slot might not be set for instances of generic methods */
2750 if (method->is_inflated) {
2751 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2752 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2753 } else {
2754 if (!is_proxy)
2755 g_assert_not_reached ();
2759 /* check method->slot is a valid index: perform isinstance? */
2760 if (method->slot != -1) {
2761 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2762 if (!is_proxy) {
2763 gboolean variance_used = FALSE;
2764 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2765 g_assert (iface_offset > 0);
2766 res = vtable [iface_offset + method->slot];
2768 } else {
2769 res = vtable [method->slot];
2773 #ifndef DISABLE_REMOTING
2774 if (is_proxy) {
2775 /* It may be an interface, abstract class method or generic method */
2776 if (!res || mono_method_signature (res)->generic_param_count)
2777 res = method;
2779 /* generic methods demand invoke_with_check */
2780 if (mono_method_signature (res)->generic_param_count)
2781 res = mono_marshal_get_remoting_invoke_with_check (res);
2782 else {
2783 #ifndef DISABLE_COM
2784 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2785 res = mono_cominterop_get_invoke (res);
2786 else
2787 #endif
2788 res = mono_marshal_get_remoting_invoke (res);
2790 } else
2791 #endif
2793 if (method->is_inflated) {
2794 MonoError error;
2795 /* Have to inflate the result */
2796 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2797 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2801 g_assert (res);
2803 return res;
2806 static MonoObject*
2807 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2809 g_error ("runtime invoke called on uninitialized runtime");
2810 return NULL;
2813 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2816 * mono_runtime_invoke:
2817 * @method: method to invoke
2818 * @obJ: object instance
2819 * @params: arguments to the method
2820 * @exc: exception information.
2822 * Invokes the method represented by @method on the object @obj.
2824 * obj is the 'this' pointer, it should be NULL for static
2825 * methods, a MonoObject* for object instances and a pointer to
2826 * the value type for value types.
2828 * The params array contains the arguments to the method with the
2829 * same convention: MonoObject* pointers for object instances and
2830 * pointers to the value type otherwise.
2832 * From unmanaged code you'll usually use the
2833 * mono_runtime_invoke() variant.
2835 * Note that this function doesn't handle virtual methods for
2836 * you, it will exec the exact method you pass: we still need to
2837 * expose a function to lookup the derived class implementation
2838 * of a virtual method (there are examples of this in the code,
2839 * though).
2841 * You can pass NULL as the exc argument if you don't want to
2842 * catch exceptions, otherwise, *exc will be set to the exception
2843 * thrown, if any. if an exception is thrown, you can't use the
2844 * MonoObject* result from the function.
2846 * If the method returns a value type, it is boxed in an object
2847 * reference.
2849 MonoObject*
2850 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2852 MonoObject *result;
2854 if (mono_runtime_get_no_exec ())
2855 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2857 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2858 mono_profiler_method_start_invoke (method);
2860 result = default_mono_runtime_invoke (method, obj, params, exc);
2862 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2863 mono_profiler_method_end_invoke (method);
2865 return result;
2869 * mono_method_get_unmanaged_thunk:
2870 * @method: method to generate a thunk for.
2872 * Returns an unmanaged->managed thunk that can be used to call
2873 * a managed method directly from C.
2875 * The thunk's C signature closely matches the managed signature:
2877 * C#: public bool Equals (object obj);
2878 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2879 * MonoObject*, MonoException**);
2881 * The 1st ("this") parameter must not be used with static methods:
2883 * C#: public static bool ReferenceEquals (object a, object b);
2884 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2885 * MonoException**);
2887 * The last argument must be a non-null pointer of a MonoException* pointer.
2888 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2889 * exception has been thrown in managed code. Otherwise it will point
2890 * to the MonoException* caught by the thunk. In this case, the result of
2891 * the thunk is undefined:
2893 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2894 * MonoException *ex = NULL;
2895 * Equals func = mono_method_get_unmanaged_thunk (method);
2896 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2897 * if (ex) {
2898 * // handle exception
2901 * The calling convention of the thunk matches the platform's default
2902 * convention. This means that under Windows, C declarations must
2903 * contain the __stdcall attribute:
2905 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2906 * MonoObject*, MonoException**);
2908 * LIMITATIONS
2910 * Value type arguments and return values are treated as they were objects:
2912 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2913 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2915 * Arguments must be properly boxed upon trunk's invocation, while return
2916 * values must be unboxed.
2918 gpointer
2919 mono_method_get_unmanaged_thunk (MonoMethod *method)
2921 method = mono_marshal_get_thunk_invoke_wrapper (method);
2922 return mono_compile_method (method);
2925 void
2926 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
2928 int t;
2929 if (type->byref) {
2930 /* object fields cannot be byref, so we don't need a
2931 wbarrier here */
2932 gpointer *p = (gpointer*)dest;
2933 *p = value;
2934 return;
2936 t = type->type;
2937 handle_enum:
2938 switch (t) {
2939 case MONO_TYPE_BOOLEAN:
2940 case MONO_TYPE_I1:
2941 case MONO_TYPE_U1: {
2942 guint8 *p = (guint8*)dest;
2943 *p = value ? *(guint8*)value : 0;
2944 return;
2946 case MONO_TYPE_I2:
2947 case MONO_TYPE_U2:
2948 case MONO_TYPE_CHAR: {
2949 guint16 *p = (guint16*)dest;
2950 *p = value ? *(guint16*)value : 0;
2951 return;
2953 #if SIZEOF_VOID_P == 4
2954 case MONO_TYPE_I:
2955 case MONO_TYPE_U:
2956 #endif
2957 case MONO_TYPE_I4:
2958 case MONO_TYPE_U4: {
2959 gint32 *p = (gint32*)dest;
2960 *p = value ? *(gint32*)value : 0;
2961 return;
2963 #if SIZEOF_VOID_P == 8
2964 case MONO_TYPE_I:
2965 case MONO_TYPE_U:
2966 #endif
2967 case MONO_TYPE_I8:
2968 case MONO_TYPE_U8: {
2969 gint64 *p = (gint64*)dest;
2970 *p = value ? *(gint64*)value : 0;
2971 return;
2973 case MONO_TYPE_R4: {
2974 float *p = (float*)dest;
2975 *p = value ? *(float*)value : 0;
2976 return;
2978 case MONO_TYPE_R8: {
2979 double *p = (double*)dest;
2980 *p = value ? *(double*)value : 0;
2981 return;
2983 case MONO_TYPE_STRING:
2984 case MONO_TYPE_SZARRAY:
2985 case MONO_TYPE_CLASS:
2986 case MONO_TYPE_OBJECT:
2987 case MONO_TYPE_ARRAY:
2988 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2989 return;
2990 case MONO_TYPE_FNPTR:
2991 case MONO_TYPE_PTR: {
2992 gpointer *p = (gpointer*)dest;
2993 *p = deref_pointer? *(gpointer*)value: value;
2994 return;
2996 case MONO_TYPE_VALUETYPE:
2997 /* note that 't' and 'type->type' can be different */
2998 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2999 t = mono_class_enum_basetype (type->data.klass)->type;
3000 goto handle_enum;
3001 } else {
3002 MonoClass *class = mono_class_from_mono_type (type);
3003 int size = mono_class_value_size (class, NULL);
3004 if (value == NULL)
3005 mono_gc_bzero_atomic (dest, size);
3006 else
3007 mono_gc_wbarrier_value_copy (dest, value, 1, class);
3009 return;
3010 case MONO_TYPE_GENERICINST:
3011 t = type->data.generic_class->container_class->byval_arg.type;
3012 goto handle_enum;
3013 default:
3014 g_error ("got type %x", type->type);
3019 * mono_field_set_value:
3020 * @obj: Instance object
3021 * @field: MonoClassField describing the field to set
3022 * @value: The value to be set
3024 * Sets the value of the field described by @field in the object instance @obj
3025 * to the value passed in @value. This method should only be used for instance
3026 * fields. For static fields, use mono_field_static_set_value.
3028 * The value must be on the native format of the field type.
3030 void
3031 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3033 void *dest;
3035 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3037 dest = (char*)obj + field->offset;
3038 mono_copy_value (field->type, dest, value, FALSE);
3042 * mono_field_static_set_value:
3043 * @field: MonoClassField describing the field to set
3044 * @value: The value to be set
3046 * Sets the value of the static field described by @field
3047 * to the value passed in @value.
3049 * The value must be on the native format of the field type.
3051 void
3052 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3054 void *dest;
3056 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3057 /* you cant set a constant! */
3058 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3060 if (field->offset == -1) {
3061 /* Special static */
3062 gpointer addr;
3064 mono_domain_lock (vt->domain);
3065 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3066 mono_domain_unlock (vt->domain);
3067 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3068 } else {
3069 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3071 mono_copy_value (field->type, dest, value, FALSE);
3075 * mono_vtable_get_static_field_data:
3077 * Internal use function: return a pointer to the memory holding the static fields
3078 * for a class or NULL if there are no static fields.
3079 * This is exported only for use by the debugger.
3081 void *
3082 mono_vtable_get_static_field_data (MonoVTable *vt)
3084 if (!vt->has_static_fields)
3085 return NULL;
3086 return vt->vtable [vt->klass->vtable_size];
3089 static guint8*
3090 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3092 guint8 *src;
3094 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3095 if (field->offset == -1) {
3096 /* Special static */
3097 gpointer addr;
3099 mono_domain_lock (vt->domain);
3100 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3101 mono_domain_unlock (vt->domain);
3102 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3103 } else {
3104 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3106 } else {
3107 src = (guint8*)obj + field->offset;
3110 return src;
3114 * mono_field_get_value:
3115 * @obj: Object instance
3116 * @field: MonoClassField describing the field to fetch information from
3117 * @value: pointer to the location where the value will be stored
3119 * Use this routine to get the value of the field @field in the object
3120 * passed.
3122 * The pointer provided by value must be of the field type, for reference
3123 * types this is a MonoObject*, for value types its the actual pointer to
3124 * the value type.
3126 * For example:
3127 * int i;
3128 * mono_field_get_value (obj, int_field, &i);
3130 void
3131 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3133 void *src;
3135 g_assert (obj);
3137 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3139 src = (char*)obj + field->offset;
3140 mono_copy_value (field->type, value, src, TRUE);
3144 * mono_field_get_value_object:
3145 * @domain: domain where the object will be created (if boxing)
3146 * @field: MonoClassField describing the field to fetch information from
3147 * @obj: The object instance for the field.
3149 * Returns: a new MonoObject with the value from the given field. If the
3150 * field represents a value type, the value is boxed.
3153 MonoObject *
3154 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3156 MonoObject *o;
3157 MonoClass *klass;
3158 MonoVTable *vtable = NULL;
3159 gchar *v;
3160 gboolean is_static = FALSE;
3161 gboolean is_ref = FALSE;
3162 gboolean is_literal = FALSE;
3163 gboolean is_ptr = FALSE;
3164 MonoError error;
3165 MonoType *type = mono_field_get_type_checked (field, &error);
3167 if (!mono_error_ok (&error))
3168 mono_error_raise_exception (&error);
3170 switch (type->type) {
3171 case MONO_TYPE_STRING:
3172 case MONO_TYPE_OBJECT:
3173 case MONO_TYPE_CLASS:
3174 case MONO_TYPE_ARRAY:
3175 case MONO_TYPE_SZARRAY:
3176 is_ref = TRUE;
3177 break;
3178 case MONO_TYPE_U1:
3179 case MONO_TYPE_I1:
3180 case MONO_TYPE_BOOLEAN:
3181 case MONO_TYPE_U2:
3182 case MONO_TYPE_I2:
3183 case MONO_TYPE_CHAR:
3184 case MONO_TYPE_U:
3185 case MONO_TYPE_I:
3186 case MONO_TYPE_U4:
3187 case MONO_TYPE_I4:
3188 case MONO_TYPE_R4:
3189 case MONO_TYPE_U8:
3190 case MONO_TYPE_I8:
3191 case MONO_TYPE_R8:
3192 case MONO_TYPE_VALUETYPE:
3193 is_ref = type->byref;
3194 break;
3195 case MONO_TYPE_GENERICINST:
3196 is_ref = !mono_type_generic_inst_is_valuetype (type);
3197 break;
3198 case MONO_TYPE_PTR:
3199 is_ptr = TRUE;
3200 break;
3201 default:
3202 g_error ("type 0x%x not handled in "
3203 "mono_field_get_value_object", type->type);
3204 return NULL;
3207 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3208 is_literal = TRUE;
3210 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3211 is_static = TRUE;
3213 if (!is_literal) {
3214 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
3215 if (!vtable->initialized)
3216 mono_runtime_class_init (vtable);
3218 } else {
3219 g_assert (obj);
3222 if (is_ref) {
3223 if (is_literal) {
3224 get_default_field_value (domain, field, &o);
3225 } else if (is_static) {
3226 mono_field_static_get_value (vtable, field, &o);
3227 } else {
3228 mono_field_get_value (obj, field, &o);
3230 return o;
3233 if (is_ptr) {
3234 static MonoMethod *m;
3235 gpointer args [2];
3236 gpointer *ptr;
3237 gpointer v;
3239 if (!m) {
3240 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3241 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3242 g_assert (m);
3245 v = &ptr;
3246 if (is_literal) {
3247 get_default_field_value (domain, field, v);
3248 } else if (is_static) {
3249 mono_field_static_get_value (vtable, field, v);
3250 } else {
3251 mono_field_get_value (obj, field, v);
3254 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3255 args [0] = ptr ? *ptr : NULL;
3256 args [1] = mono_type_get_object (mono_domain_get (), type);
3258 return mono_runtime_invoke (m, NULL, args, NULL);
3261 /* boxed value type */
3262 klass = mono_class_from_mono_type (type);
3264 if (mono_class_is_nullable (klass))
3265 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3267 o = mono_object_new (domain, klass);
3268 v = ((gchar *) o) + sizeof (MonoObject);
3270 if (is_literal) {
3271 get_default_field_value (domain, field, v);
3272 } else if (is_static) {
3273 mono_field_static_get_value (vtable, field, v);
3274 } else {
3275 mono_field_get_value (obj, field, v);
3278 return o;
3282 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3284 int retval = 0;
3285 const char *p = blob;
3286 mono_metadata_decode_blob_size (p, &p);
3288 switch (type) {
3289 case MONO_TYPE_BOOLEAN:
3290 case MONO_TYPE_U1:
3291 case MONO_TYPE_I1:
3292 *(guint8 *) value = *p;
3293 break;
3294 case MONO_TYPE_CHAR:
3295 case MONO_TYPE_U2:
3296 case MONO_TYPE_I2:
3297 *(guint16*) value = read16 (p);
3298 break;
3299 case MONO_TYPE_U4:
3300 case MONO_TYPE_I4:
3301 *(guint32*) value = read32 (p);
3302 break;
3303 case MONO_TYPE_U8:
3304 case MONO_TYPE_I8:
3305 *(guint64*) value = read64 (p);
3306 break;
3307 case MONO_TYPE_R4:
3308 readr4 (p, (float*) value);
3309 break;
3310 case MONO_TYPE_R8:
3311 readr8 (p, (double*) value);
3312 break;
3313 case MONO_TYPE_STRING:
3314 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3315 break;
3316 case MONO_TYPE_CLASS:
3317 *(gpointer*) value = NULL;
3318 break;
3319 default:
3320 retval = -1;
3321 g_warning ("type 0x%02x should not be in constant table", type);
3323 return retval;
3326 static void
3327 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3329 MonoTypeEnum def_type;
3330 const char* data;
3332 data = mono_class_get_field_default_value (field, &def_type);
3333 mono_get_constant_value_from_blob (domain, def_type, data, value);
3336 void
3337 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3339 void *src;
3341 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3343 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3344 get_default_field_value (vt->domain, field, value);
3345 return;
3348 if (field->offset == -1) {
3349 /* Special static */
3350 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3351 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3352 } else {
3353 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3355 mono_copy_value (field->type, value, src, TRUE);
3359 * mono_field_static_get_value:
3360 * @vt: vtable to the object
3361 * @field: MonoClassField describing the field to fetch information from
3362 * @value: where the value is returned
3364 * Use this routine to get the value of the static field @field value.
3366 * The pointer provided by value must be of the field type, for reference
3367 * types this is a MonoObject*, for value types its the actual pointer to
3368 * the value type.
3370 * For example:
3371 * int i;
3372 * mono_field_static_get_value (vt, int_field, &i);
3374 void
3375 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3377 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3381 * mono_property_set_value:
3382 * @prop: MonoProperty to set
3383 * @obj: instance object on which to act
3384 * @params: parameters to pass to the propery
3385 * @exc: optional exception
3387 * Invokes the property's set method with the given arguments on the
3388 * object instance obj (or NULL for static properties).
3390 * You can pass NULL as the exc argument if you don't want to
3391 * catch exceptions, otherwise, *exc will be set to the exception
3392 * thrown, if any. if an exception is thrown, you can't use the
3393 * MonoObject* result from the function.
3395 void
3396 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3398 default_mono_runtime_invoke (prop->set, obj, params, exc);
3402 * mono_property_get_value:
3403 * @prop: MonoProperty to fetch
3404 * @obj: instance object on which to act
3405 * @params: parameters to pass to the propery
3406 * @exc: optional exception
3408 * Invokes the property's get method with the given arguments on the
3409 * object instance obj (or NULL for static properties).
3411 * You can pass NULL as the exc argument if you don't want to
3412 * catch exceptions, otherwise, *exc will be set to the exception
3413 * thrown, if any. if an exception is thrown, you can't use the
3414 * MonoObject* result from the function.
3416 * Returns: the value from invoking the get method on the property.
3418 MonoObject*
3419 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3421 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3425 * mono_nullable_init:
3426 * @buf: The nullable structure to initialize.
3427 * @value: the value to initialize from
3428 * @klass: the type for the object
3430 * Initialize the nullable structure pointed to by @buf from @value which
3431 * should be a boxed value type. The size of @buf should be able to hold
3432 * as much data as the @klass->instance_size (which is the number of bytes
3433 * that will be copies).
3435 * Since Nullables have variable structure, we can not define a C
3436 * structure for them.
3438 void
3439 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3441 MonoClass *param_class = klass->cast_class;
3443 mono_class_setup_fields_locking (klass);
3444 g_assert (klass->fields_inited);
3446 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3447 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3449 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3450 if (value) {
3451 if (param_class->has_references)
3452 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3453 else
3454 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3455 } else {
3456 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3461 * mono_nullable_box:
3462 * @buf: The buffer representing the data to be boxed
3463 * @klass: the type to box it as.
3465 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3466 * @buf.
3468 MonoObject*
3469 mono_nullable_box (guint8 *buf, MonoClass *klass)
3471 MonoClass *param_class = klass->cast_class;
3473 mono_class_setup_fields_locking (klass);
3474 g_assert (klass->fields_inited);
3476 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3477 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3479 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3480 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3481 if (param_class->has_references)
3482 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3483 else
3484 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3485 return o;
3487 else
3488 return NULL;
3492 * mono_get_delegate_invoke:
3493 * @klass: The delegate class
3495 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3497 MonoMethod *
3498 mono_get_delegate_invoke (MonoClass *klass)
3500 MonoMethod *im;
3502 /* This is called at runtime, so avoid the slower search in metadata */
3503 mono_class_setup_methods (klass);
3504 if (klass->exception_type)
3505 return NULL;
3506 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3507 return im;
3511 * mono_get_delegate_begin_invoke:
3512 * @klass: The delegate class
3514 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3516 MonoMethod *
3517 mono_get_delegate_begin_invoke (MonoClass *klass)
3519 MonoMethod *im;
3521 /* This is called at runtime, so avoid the slower search in metadata */
3522 mono_class_setup_methods (klass);
3523 if (klass->exception_type)
3524 return NULL;
3525 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3526 return im;
3530 * mono_get_delegate_end_invoke:
3531 * @klass: The delegate class
3533 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3535 MonoMethod *
3536 mono_get_delegate_end_invoke (MonoClass *klass)
3538 MonoMethod *im;
3540 /* This is called at runtime, so avoid the slower search in metadata */
3541 mono_class_setup_methods (klass);
3542 if (klass->exception_type)
3543 return NULL;
3544 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3545 return im;
3549 * mono_runtime_delegate_invoke:
3550 * @delegate: pointer to a delegate object.
3551 * @params: parameters for the delegate.
3552 * @exc: Pointer to the exception result.
3554 * Invokes the delegate method @delegate with the parameters provided.
3556 * You can pass NULL as the exc argument if you don't want to
3557 * catch exceptions, otherwise, *exc will be set to the exception
3558 * thrown, if any. if an exception is thrown, you can't use the
3559 * MonoObject* result from the function.
3561 MonoObject*
3562 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3564 MonoMethod *im;
3565 MonoClass *klass = delegate->vtable->klass;
3567 im = mono_get_delegate_invoke (klass);
3568 if (!im)
3569 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3571 return mono_runtime_invoke (im, delegate, params, exc);
3574 static char **main_args = NULL;
3575 static int num_main_args = 0;
3578 * mono_runtime_get_main_args:
3580 * Returns: a MonoArray with the arguments passed to the main program
3582 MonoArray*
3583 mono_runtime_get_main_args (void)
3585 MonoArray *res;
3586 int i;
3587 MonoDomain *domain = mono_domain_get ();
3589 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3591 for (i = 0; i < num_main_args; ++i)
3592 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3594 return res;
3597 static void
3598 free_main_args (void)
3600 int i;
3602 for (i = 0; i < num_main_args; ++i)
3603 g_free (main_args [i]);
3604 g_free (main_args);
3605 num_main_args = 0;
3606 main_args = NULL;
3610 * mono_runtime_set_main_args:
3611 * @argc: number of arguments from the command line
3612 * @argv: array of strings from the command line
3614 * Set the command line arguments from an embedding application that doesn't otherwise call
3615 * mono_runtime_run_main ().
3618 mono_runtime_set_main_args (int argc, char* argv[])
3620 int i;
3622 free_main_args ();
3623 main_args = g_new0 (char*, argc);
3624 num_main_args = argc;
3626 for (i = 0; i < argc; ++i) {
3627 gchar *utf8_arg;
3629 utf8_arg = mono_utf8_from_external (argv[i]);
3630 if (utf8_arg == NULL) {
3631 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3632 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3633 exit (-1);
3636 main_args [i] = utf8_arg;
3639 return 0;
3643 * mono_runtime_run_main:
3644 * @method: the method to start the application with (usually Main)
3645 * @argc: number of arguments from the command line
3646 * @argv: array of strings from the command line
3647 * @exc: excetption results
3649 * Execute a standard Main() method (argc/argv contains the
3650 * executable name). This method also sets the command line argument value
3651 * needed by System.Environment.
3656 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3657 MonoObject **exc)
3659 int i;
3660 MonoArray *args = NULL;
3661 MonoDomain *domain = mono_domain_get ();
3662 gchar *utf8_fullpath;
3663 MonoMethodSignature *sig;
3665 g_assert (method != NULL);
3667 mono_thread_set_main (mono_thread_current ());
3669 main_args = g_new0 (char*, argc);
3670 num_main_args = argc;
3672 if (!g_path_is_absolute (argv [0])) {
3673 gchar *basename = g_path_get_basename (argv [0]);
3674 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3675 basename,
3676 NULL);
3678 utf8_fullpath = mono_utf8_from_external (fullpath);
3679 if(utf8_fullpath == NULL) {
3680 /* Printing the arg text will cause glib to
3681 * whinge about "Invalid UTF-8", but at least
3682 * its relevant, and shows the problem text
3683 * string.
3685 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3686 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3687 exit (-1);
3690 g_free (fullpath);
3691 g_free (basename);
3692 } else {
3693 utf8_fullpath = mono_utf8_from_external (argv[0]);
3694 if(utf8_fullpath == NULL) {
3695 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3696 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3697 exit (-1);
3701 main_args [0] = utf8_fullpath;
3703 for (i = 1; i < argc; ++i) {
3704 gchar *utf8_arg;
3706 utf8_arg=mono_utf8_from_external (argv[i]);
3707 if(utf8_arg==NULL) {
3708 /* Ditto the comment about Invalid UTF-8 here */
3709 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3710 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3711 exit (-1);
3714 main_args [i] = utf8_arg;
3716 argc--;
3717 argv++;
3719 sig = mono_method_signature (method);
3720 if (!sig) {
3721 g_print ("Unable to load Main method.\n");
3722 exit (-1);
3725 if (sig->param_count) {
3726 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3727 for (i = 0; i < argc; ++i) {
3728 /* The encodings should all work, given that
3729 * we've checked all these args for the
3730 * main_args array.
3732 gchar *str = mono_utf8_from_external (argv [i]);
3733 MonoString *arg = mono_string_new (domain, str);
3734 mono_array_setref (args, i, arg);
3735 g_free (str);
3737 } else {
3738 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3741 mono_assembly_set_main (method->klass->image->assembly);
3743 return mono_runtime_exec_main (method, args, exc);
3746 static MonoObject*
3747 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3749 static MonoMethod *serialize_method;
3751 void *params [1];
3752 MonoObject *array;
3754 if (!serialize_method) {
3755 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3756 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3759 if (!serialize_method) {
3760 *failure = TRUE;
3761 return NULL;
3764 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
3766 params [0] = obj;
3767 *exc = NULL;
3768 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3769 if (*exc)
3770 *failure = TRUE;
3772 return array;
3775 static MonoObject*
3776 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3778 static MonoMethod *deserialize_method;
3780 void *params [1];
3781 MonoObject *result;
3783 if (!deserialize_method) {
3784 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3785 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3787 if (!deserialize_method) {
3788 *failure = TRUE;
3789 return NULL;
3792 params [0] = obj;
3793 *exc = NULL;
3794 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3795 if (*exc)
3796 *failure = TRUE;
3798 return result;
3801 #ifndef DISABLE_REMOTING
3802 static MonoObject*
3803 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3805 static MonoMethod *get_proxy_method;
3807 MonoDomain *domain = mono_domain_get ();
3808 MonoRealProxy *real_proxy;
3809 MonoReflectionType *reflection_type;
3810 MonoTransparentProxy *transparent_proxy;
3812 if (!get_proxy_method)
3813 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3815 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
3817 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3818 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3820 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3821 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3823 *exc = NULL;
3824 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3825 if (*exc)
3826 *failure = TRUE;
3828 return (MonoObject*) transparent_proxy;
3830 #endif /* DISABLE_REMOTING */
3833 * mono_object_xdomain_representation
3834 * @obj: an object
3835 * @target_domain: a domain
3836 * @exc: pointer to a MonoObject*
3838 * Creates a representation of obj in the domain target_domain. This
3839 * is either a copy of obj arrived through via serialization and
3840 * deserialization or a proxy, depending on whether the object is
3841 * serializable or marshal by ref. obj must not be in target_domain.
3843 * If the object cannot be represented in target_domain, NULL is
3844 * returned and *exc is set to an appropriate exception.
3846 MonoObject*
3847 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3849 MonoObject *deserialized = NULL;
3850 gboolean failure = FALSE;
3852 *exc = NULL;
3854 #ifndef DISABLE_REMOTING
3855 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
3856 deserialized = make_transparent_proxy (obj, &failure, exc);
3858 else
3859 #endif
3861 MonoDomain *domain = mono_domain_get ();
3862 MonoObject *serialized;
3864 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3865 serialized = serialize_object (obj, &failure, exc);
3866 mono_domain_set_internal_with_options (target_domain, FALSE);
3867 if (!failure)
3868 deserialized = deserialize_object (serialized, &failure, exc);
3869 if (domain != target_domain)
3870 mono_domain_set_internal_with_options (domain, FALSE);
3873 return deserialized;
3876 /* Used in call_unhandled_exception_delegate */
3877 static MonoObject *
3878 create_unhandled_exception_eventargs (MonoObject *exc)
3880 MonoClass *klass;
3881 gpointer args [2];
3882 MonoMethod *method = NULL;
3883 MonoBoolean is_terminating = TRUE;
3884 MonoObject *obj;
3886 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3887 g_assert (klass);
3889 mono_class_init (klass);
3891 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3892 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3893 g_assert (method);
3895 args [0] = exc;
3896 args [1] = &is_terminating;
3898 obj = mono_object_new (mono_domain_get (), klass);
3899 mono_runtime_invoke (method, obj, args, NULL);
3901 return obj;
3904 /* Used in mono_unhandled_exception */
3905 static void
3906 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3907 MonoObject *e = NULL;
3908 gpointer pa [2];
3909 MonoDomain *current_domain = mono_domain_get ();
3911 if (domain != current_domain)
3912 mono_domain_set_internal_with_options (domain, FALSE);
3914 g_assert (domain == mono_object_domain (domain->domain));
3916 if (mono_object_domain (exc) != domain) {
3917 MonoObject *serialization_exc;
3919 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3920 if (!exc) {
3921 if (serialization_exc) {
3922 MonoObject *dummy;
3923 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3924 g_assert (exc);
3925 } else {
3926 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3927 "System.Runtime.Serialization", "SerializationException",
3928 "Could not serialize unhandled exception.");
3932 g_assert (mono_object_domain (exc) == domain);
3934 pa [0] = domain->domain;
3935 pa [1] = create_unhandled_exception_eventargs (exc);
3936 mono_runtime_delegate_invoke (delegate, pa, &e);
3938 if (domain != current_domain)
3939 mono_domain_set_internal_with_options (current_domain, FALSE);
3941 if (e) {
3942 MonoError error;
3943 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3944 if (!mono_error_ok (&error)) {
3945 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3946 mono_error_cleanup (&error);
3947 } else {
3948 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3949 g_free (msg);
3954 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3957 * mono_runtime_unhandled_exception_policy_set:
3958 * @policy: the new policy
3960 * This is a VM internal routine.
3962 * Sets the runtime policy for handling unhandled exceptions.
3964 void
3965 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3966 runtime_unhandled_exception_policy = policy;
3970 * mono_runtime_unhandled_exception_policy_get:
3972 * This is a VM internal routine.
3974 * Gets the runtime policy for handling unhandled exceptions.
3976 MonoRuntimeUnhandledExceptionPolicy
3977 mono_runtime_unhandled_exception_policy_get (void) {
3978 return runtime_unhandled_exception_policy;
3982 * mono_unhandled_exception:
3983 * @exc: exception thrown
3985 * This is a VM internal routine.
3987 * We call this function when we detect an unhandled exception
3988 * in the default domain.
3990 * It invokes the * UnhandledException event in AppDomain or prints
3991 * a warning to the console
3993 void
3994 mono_unhandled_exception (MonoObject *exc)
3996 MonoDomain *current_domain = mono_domain_get ();
3997 MonoDomain *root_domain = mono_get_root_domain ();
3998 MonoClassField *field;
3999 MonoObject *current_appdomain_delegate;
4000 MonoObject *root_appdomain_delegate;
4002 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
4003 "UnhandledException");
4004 g_assert (field);
4006 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
4007 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
4008 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
4009 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
4010 if (current_domain != root_domain) {
4011 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
4012 } else {
4013 current_appdomain_delegate = NULL;
4016 /* set exitcode only if we will abort the process */
4017 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
4018 if (abort_process)
4019 mono_environment_exitcode_set (1);
4020 mono_print_unhandled_exception (exc);
4021 } else {
4022 if (root_appdomain_delegate) {
4023 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4025 if (current_appdomain_delegate) {
4026 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4033 * mono_runtime_exec_managed_code:
4034 * @domain: Application domain
4035 * @main_func: function to invoke from the execution thread
4036 * @main_args: parameter to the main_func
4038 * Launch a new thread to execute a function
4040 * main_func is called back from the thread with main_args as the
4041 * parameter. The callback function is expected to start Main()
4042 * eventually. This function then waits for all managed threads to
4043 * finish.
4044 * It is not necesseray anymore to execute managed code in a subthread,
4045 * so this function should not be used anymore by default: just
4046 * execute the code and then call mono_thread_manage ().
4048 void
4049 mono_runtime_exec_managed_code (MonoDomain *domain,
4050 MonoMainThreadFunc main_func,
4051 gpointer main_args)
4053 mono_thread_create (domain, main_func, main_args);
4055 mono_thread_manage ();
4059 * Execute a standard Main() method (args doesn't contain the
4060 * executable name).
4063 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4065 MonoDomain *domain;
4066 gpointer pa [1];
4067 int rval;
4068 MonoCustomAttrInfo* cinfo;
4069 gboolean has_stathread_attribute;
4070 MonoInternalThread* thread = mono_thread_internal_current ();
4072 g_assert (args);
4074 pa [0] = args;
4076 domain = mono_object_domain (args);
4077 if (!domain->entry_assembly) {
4078 gchar *str;
4079 MonoAssembly *assembly;
4081 assembly = method->klass->image->assembly;
4082 domain->entry_assembly = assembly;
4083 /* Domains created from another domain already have application_base and configuration_file set */
4084 if (domain->setup->application_base == NULL) {
4085 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4088 if (domain->setup->configuration_file == NULL) {
4089 str = g_strconcat (assembly->image->name, ".config", NULL);
4090 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4091 g_free (str);
4092 mono_set_private_bin_path_from_config (domain);
4096 cinfo = mono_custom_attrs_from_method (method);
4097 if (cinfo) {
4098 static MonoClass *stathread_attribute = NULL;
4099 if (!stathread_attribute)
4100 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
4101 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
4102 if (!cinfo->cached)
4103 mono_custom_attrs_free (cinfo);
4104 } else {
4105 has_stathread_attribute = FALSE;
4107 if (has_stathread_attribute) {
4108 thread->apartment_state = ThreadApartmentState_STA;
4109 } else {
4110 thread->apartment_state = ThreadApartmentState_MTA;
4112 mono_thread_init_apartment_state ();
4114 /* FIXME: check signature of method */
4115 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4116 MonoObject *res;
4117 res = mono_runtime_invoke (method, NULL, pa, exc);
4118 if (!exc || !*exc)
4119 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4120 else
4121 rval = -1;
4123 mono_environment_exitcode_set (rval);
4124 } else {
4125 mono_runtime_invoke (method, NULL, pa, exc);
4126 if (!exc || !*exc)
4127 rval = 0;
4128 else {
4129 /* If the return type of Main is void, only
4130 * set the exitcode if an exception was thrown
4131 * (we don't want to blow away an
4132 * explicitly-set exit code)
4134 rval = -1;
4135 mono_environment_exitcode_set (rval);
4139 return rval;
4143 * mono_install_runtime_invoke:
4144 * @func: Function to install
4146 * This is a VM internal routine
4148 void
4149 mono_install_runtime_invoke (MonoInvokeFunc func)
4151 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4156 * mono_runtime_invoke_array:
4157 * @method: method to invoke
4158 * @obJ: object instance
4159 * @params: arguments to the method
4160 * @exc: exception information.
4162 * Invokes the method represented by @method on the object @obj.
4164 * obj is the 'this' pointer, it should be NULL for static
4165 * methods, a MonoObject* for object instances and a pointer to
4166 * the value type for value types.
4168 * The params array contains the arguments to the method with the
4169 * same convention: MonoObject* pointers for object instances and
4170 * pointers to the value type otherwise. The _invoke_array
4171 * variant takes a C# object[] as the params argument (MonoArray
4172 * *params): in this case the value types are boxed inside the
4173 * respective reference representation.
4175 * From unmanaged code you'll usually use the
4176 * mono_runtime_invoke() variant.
4178 * Note that this function doesn't handle virtual methods for
4179 * you, it will exec the exact method you pass: we still need to
4180 * expose a function to lookup the derived class implementation
4181 * of a virtual method (there are examples of this in the code,
4182 * though).
4184 * You can pass NULL as the exc argument if you don't want to
4185 * catch exceptions, otherwise, *exc will be set to the exception
4186 * thrown, if any. if an exception is thrown, you can't use the
4187 * MonoObject* result from the function.
4189 * If the method returns a value type, it is boxed in an object
4190 * reference.
4192 MonoObject*
4193 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4194 MonoObject **exc)
4196 MonoMethodSignature *sig = mono_method_signature (method);
4197 gpointer *pa = NULL;
4198 MonoObject *res;
4199 int i;
4200 gboolean has_byref_nullables = FALSE;
4202 if (NULL != params) {
4203 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4204 for (i = 0; i < mono_array_length (params); i++) {
4205 MonoType *t = sig->params [i];
4207 again:
4208 switch (t->type) {
4209 case MONO_TYPE_U1:
4210 case MONO_TYPE_I1:
4211 case MONO_TYPE_BOOLEAN:
4212 case MONO_TYPE_U2:
4213 case MONO_TYPE_I2:
4214 case MONO_TYPE_CHAR:
4215 case MONO_TYPE_U:
4216 case MONO_TYPE_I:
4217 case MONO_TYPE_U4:
4218 case MONO_TYPE_I4:
4219 case MONO_TYPE_U8:
4220 case MONO_TYPE_I8:
4221 case MONO_TYPE_R4:
4222 case MONO_TYPE_R8:
4223 case MONO_TYPE_VALUETYPE:
4224 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4225 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4226 pa [i] = mono_array_get (params, MonoObject*, i);
4227 if (t->byref)
4228 has_byref_nullables = TRUE;
4229 } else {
4230 /* MS seems to create the objects if a null is passed in */
4231 if (!mono_array_get (params, MonoObject*, i))
4232 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4234 if (t->byref) {
4236 * We can't pass the unboxed vtype byref to the callee, since
4237 * that would mean the callee would be able to modify boxed
4238 * primitive types. So we (and MS) make a copy of the boxed
4239 * object, pass that to the callee, and replace the original
4240 * boxed object in the arg array with the copy.
4242 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4243 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4244 mono_array_setref (params, i, copy);
4247 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4249 break;
4250 case MONO_TYPE_STRING:
4251 case MONO_TYPE_OBJECT:
4252 case MONO_TYPE_CLASS:
4253 case MONO_TYPE_ARRAY:
4254 case MONO_TYPE_SZARRAY:
4255 if (t->byref)
4256 pa [i] = mono_array_addr (params, MonoObject*, i);
4257 // FIXME: I need to check this code path
4258 else
4259 pa [i] = mono_array_get (params, MonoObject*, i);
4260 break;
4261 case MONO_TYPE_GENERICINST:
4262 if (t->byref)
4263 t = &t->data.generic_class->container_class->this_arg;
4264 else
4265 t = &t->data.generic_class->container_class->byval_arg;
4266 goto again;
4267 case MONO_TYPE_PTR: {
4268 MonoObject *arg;
4270 /* The argument should be an IntPtr */
4271 arg = mono_array_get (params, MonoObject*, i);
4272 if (arg == NULL) {
4273 pa [i] = NULL;
4274 } else {
4275 g_assert (arg->vtable->klass == mono_defaults.int_class);
4276 pa [i] = ((MonoIntPtr*)arg)->m_value;
4278 break;
4280 default:
4281 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4286 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4287 void *o = obj;
4289 if (mono_class_is_nullable (method->klass)) {
4290 /* Need to create a boxed vtype instead */
4291 g_assert (!obj);
4293 if (!params)
4294 return NULL;
4295 else
4296 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4299 if (!obj) {
4300 obj = mono_object_new (mono_domain_get (), method->klass);
4301 g_assert (obj); /*maybe we should raise a TLE instead?*/
4302 #ifndef DISABLE_REMOTING
4303 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4304 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4306 #endif
4307 if (method->klass->valuetype)
4308 o = mono_object_unbox (obj);
4309 else
4310 o = obj;
4311 } else if (method->klass->valuetype) {
4312 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4315 mono_runtime_invoke (method, o, pa, exc);
4316 return obj;
4317 } else {
4318 if (mono_class_is_nullable (method->klass)) {
4319 MonoObject *nullable;
4321 /* Convert the unboxed vtype into a Nullable structure */
4322 nullable = mono_object_new (mono_domain_get (), method->klass);
4324 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4325 obj = mono_object_unbox (nullable);
4328 /* obj must be already unboxed if needed */
4329 res = mono_runtime_invoke (method, obj, pa, exc);
4331 if (sig->ret->type == MONO_TYPE_PTR) {
4332 MonoClass *pointer_class;
4333 static MonoMethod *box_method;
4334 void *box_args [2];
4335 MonoObject *box_exc;
4338 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4339 * convert it to a Pointer object.
4341 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4342 if (!box_method)
4343 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4345 g_assert (res->vtable->klass == mono_defaults.int_class);
4346 box_args [0] = ((MonoIntPtr*)res)->m_value;
4347 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4348 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4349 g_assert (!box_exc);
4352 if (has_byref_nullables) {
4354 * The runtime invoke wrapper already converted byref nullables back,
4355 * and stored them in pa, we just need to copy them back to the
4356 * managed array.
4358 for (i = 0; i < mono_array_length (params); i++) {
4359 MonoType *t = sig->params [i];
4361 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4362 mono_array_setref (params, i, pa [i]);
4366 return res;
4370 static void
4371 arith_overflow (void)
4373 mono_raise_exception (mono_get_exception_overflow ());
4377 * mono_object_allocate:
4378 * @size: number of bytes to allocate
4380 * This is a very simplistic routine until we have our GC-aware
4381 * memory allocator.
4383 * Returns: an allocated object of size @size, or NULL on failure.
4385 static inline void *
4386 mono_object_allocate (size_t size, MonoVTable *vtable)
4388 MonoObject *o;
4389 ALLOC_OBJECT (o, vtable, size);
4391 return o;
4394 #ifndef HAVE_SGEN_GC
4396 * mono_object_allocate_ptrfree:
4397 * @size: number of bytes to allocate
4399 * Note that the memory allocated is not zeroed.
4400 * Returns: an allocated object of size @size, or NULL on failure.
4402 static inline void *
4403 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4405 MonoObject *o;
4406 ALLOC_PTRFREE (o, vtable, size);
4407 return o;
4409 #endif
4411 static inline void *
4412 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4414 void *o;
4415 ALLOC_TYPED (o, size, vtable);
4417 return o;
4421 * mono_object_new:
4422 * @klass: the class of the object that we want to create
4424 * Returns: a newly created object whose definition is
4425 * looked up using @klass. This will not invoke any constructors,
4426 * so the consumer of this routine has to invoke any constructors on
4427 * its own to initialize the object.
4429 * It returns NULL on failure.
4431 MonoObject *
4432 mono_object_new (MonoDomain *domain, MonoClass *klass)
4434 MonoVTable *vtable;
4436 vtable = mono_class_vtable (domain, klass);
4437 if (!vtable)
4438 return NULL;
4439 return mono_object_new_specific (vtable);
4443 * mono_object_new_pinned:
4445 * Same as mono_object_new, but the returned object will be pinned.
4446 * For SGEN, these objects will only be freed at appdomain unload.
4448 MonoObject *
4449 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4451 MonoVTable *vtable;
4453 vtable = mono_class_vtable (domain, klass);
4454 if (!vtable)
4455 return NULL;
4457 #ifdef HAVE_SGEN_GC
4458 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4459 #else
4460 return mono_object_new_specific (vtable);
4461 #endif
4465 * mono_object_new_specific:
4466 * @vtable: the vtable of the object that we want to create
4468 * Returns: A newly created object with class and domain specified
4469 * by @vtable
4471 MonoObject *
4472 mono_object_new_specific (MonoVTable *vtable)
4474 MonoObject *o;
4476 /* check for is_com_object for COM Interop */
4477 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4479 gpointer pa [1];
4480 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4482 if (im == NULL) {
4483 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4485 if (!klass->inited)
4486 mono_class_init (klass);
4488 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4489 g_assert (im);
4490 vtable->domain->create_proxy_for_type_method = im;
4493 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4495 o = mono_runtime_invoke (im, NULL, pa, NULL);
4496 if (o != NULL) return o;
4499 return mono_object_new_alloc_specific (vtable);
4502 MonoObject *
4503 mono_object_new_alloc_specific (MonoVTable *vtable)
4505 MonoObject *o;
4507 if (!vtable->klass->has_references) {
4508 o = mono_object_new_ptrfree (vtable);
4509 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4510 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4511 } else {
4512 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4513 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4515 if (G_UNLIKELY (vtable->klass->has_finalize))
4516 mono_object_register_finalizer (o);
4518 if (G_UNLIKELY (profile_allocs))
4519 mono_profiler_allocation (o, vtable->klass);
4520 return o;
4523 MonoObject*
4524 mono_object_new_fast (MonoVTable *vtable)
4526 MonoObject *o;
4527 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4528 return o;
4531 static MonoObject*
4532 mono_object_new_ptrfree (MonoVTable *vtable)
4534 MonoObject *obj;
4535 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4536 #if NEED_TO_ZERO_PTRFREE
4537 /* an inline memset is much faster for the common vcase of small objects
4538 * note we assume the allocated size is a multiple of sizeof (void*).
4540 if (vtable->klass->instance_size < 128) {
4541 gpointer *p, *end;
4542 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4543 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4544 while (p < end) {
4545 *p = NULL;
4546 ++p;
4548 } else {
4549 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4551 #endif
4552 return obj;
4555 static MonoObject*
4556 mono_object_new_ptrfree_box (MonoVTable *vtable)
4558 MonoObject *obj;
4559 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4560 /* the object will be boxed right away, no need to memzero it */
4561 return obj;
4565 * mono_class_get_allocation_ftn:
4566 * @vtable: vtable
4567 * @for_box: the object will be used for boxing
4568 * @pass_size_in_words:
4570 * Return the allocation function appropriate for the given class.
4573 void*
4574 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4576 *pass_size_in_words = FALSE;
4578 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4579 profile_allocs = FALSE;
4581 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4582 return mono_object_new_specific;
4584 if (!vtable->klass->has_references) {
4585 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4586 if (for_box)
4587 return mono_object_new_ptrfree_box;
4588 return mono_object_new_ptrfree;
4591 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4593 return mono_object_new_fast;
4596 * FIXME: This is actually slower than mono_object_new_fast, because
4597 * of the overhead of parameter passing.
4600 *pass_size_in_words = TRUE;
4601 #ifdef GC_REDIRECT_TO_LOCAL
4602 return GC_local_gcj_fast_malloc;
4603 #else
4604 return GC_gcj_fast_malloc;
4605 #endif
4609 return mono_object_new_specific;
4613 * mono_object_new_from_token:
4614 * @image: Context where the type_token is hosted
4615 * @token: a token of the type that we want to create
4617 * Returns: A newly created object whose definition is
4618 * looked up using @token in the @image image
4620 MonoObject *
4621 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4623 MonoError error;
4624 MonoClass *class;
4626 class = mono_class_get_checked (image, token, &error);
4627 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
4629 return mono_object_new (domain, class);
4634 * mono_object_clone:
4635 * @obj: the object to clone
4637 * Returns: A newly created object who is a shallow copy of @obj
4639 MonoObject *
4640 mono_object_clone (MonoObject *obj)
4642 MonoObject *o;
4643 int size = obj->vtable->klass->instance_size;
4645 if (obj->vtable->klass->rank)
4646 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4648 o = mono_object_allocate (size, obj->vtable);
4650 if (obj->vtable->klass->has_references) {
4651 mono_gc_wbarrier_object_copy (o, obj);
4652 } else {
4653 int size = obj->vtable->klass->instance_size;
4654 /* do not copy the sync state */
4655 mono_gc_memmove_atomic ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4657 if (G_UNLIKELY (profile_allocs))
4658 mono_profiler_allocation (o, obj->vtable->klass);
4660 if (obj->vtable->klass->has_finalize)
4661 mono_object_register_finalizer (o);
4662 return o;
4666 * mono_array_full_copy:
4667 * @src: source array to copy
4668 * @dest: destination array
4670 * Copies the content of one array to another with exactly the same type and size.
4672 void
4673 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4675 uintptr_t size;
4676 MonoClass *klass = src->obj.vtable->klass;
4678 g_assert (klass == dest->obj.vtable->klass);
4680 size = mono_array_length (src);
4681 g_assert (size == mono_array_length (dest));
4682 size *= mono_array_element_size (klass);
4683 #ifdef HAVE_SGEN_GC
4684 if (klass->element_class->valuetype) {
4685 if (klass->element_class->has_references)
4686 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
4687 else
4688 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4689 } else {
4690 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4692 #else
4693 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4694 #endif
4698 * mono_array_clone_in_domain:
4699 * @domain: the domain in which the array will be cloned into
4700 * @array: the array to clone
4702 * This routine returns a copy of the array that is hosted on the
4703 * specified MonoDomain.
4705 MonoArray*
4706 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4708 MonoArray *o;
4709 uintptr_t size, i;
4710 uintptr_t *sizes;
4711 MonoClass *klass = array->obj.vtable->klass;
4713 if (array->bounds == NULL) {
4714 size = mono_array_length (array);
4715 o = mono_array_new_full (domain, klass, &size, NULL);
4717 size *= mono_array_element_size (klass);
4718 #ifdef HAVE_SGEN_GC
4719 if (klass->element_class->valuetype) {
4720 if (klass->element_class->has_references)
4721 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4722 else
4723 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4724 } else {
4725 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4727 #else
4728 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4729 #endif
4730 return o;
4733 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4734 size = mono_array_element_size (klass);
4735 for (i = 0; i < klass->rank; ++i) {
4736 sizes [i] = array->bounds [i].length;
4737 size *= array->bounds [i].length;
4738 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4740 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4741 #ifdef HAVE_SGEN_GC
4742 if (klass->element_class->valuetype) {
4743 if (klass->element_class->has_references)
4744 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4745 else
4746 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4747 } else {
4748 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4750 #else
4751 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4752 #endif
4754 return o;
4758 * mono_array_clone:
4759 * @array: the array to clone
4761 * Returns: A newly created array who is a shallow copy of @array
4763 MonoArray*
4764 mono_array_clone (MonoArray *array)
4766 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4769 /* helper macros to check for overflow when calculating the size of arrays */
4770 #ifdef MONO_BIG_ARRAYS
4771 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4772 #define MYGUINT_MAX MYGUINT64_MAX
4773 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4774 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4775 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4776 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4777 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4778 #else
4779 #define MYGUINT32_MAX 4294967295U
4780 #define MYGUINT_MAX MYGUINT32_MAX
4781 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4782 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4783 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4784 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4785 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4786 #endif
4788 gboolean
4789 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4791 uintptr_t byte_len;
4793 byte_len = mono_array_element_size (class);
4794 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4795 return FALSE;
4796 byte_len *= len;
4797 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4798 return FALSE;
4799 byte_len += sizeof (MonoArray);
4801 *res = byte_len;
4803 return TRUE;
4807 * mono_array_new_full:
4808 * @domain: domain where the object is created
4809 * @array_class: array class
4810 * @lengths: lengths for each dimension in the array
4811 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4813 * This routine creates a new array objects with the given dimensions,
4814 * lower bounds and type.
4816 MonoArray*
4817 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4819 uintptr_t byte_len = 0, len, bounds_size;
4820 MonoObject *o;
4821 MonoArray *array;
4822 MonoArrayBounds *bounds;
4823 MonoVTable *vtable;
4824 int i;
4826 if (!array_class->inited)
4827 mono_class_init (array_class);
4829 len = 1;
4831 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4832 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4833 len = lengths [0];
4834 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4835 arith_overflow ();
4836 bounds_size = 0;
4837 } else {
4838 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4840 for (i = 0; i < array_class->rank; ++i) {
4841 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4842 arith_overflow ();
4843 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4844 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4845 len *= lengths [i];
4849 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4850 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4852 if (bounds_size) {
4853 /* align */
4854 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4855 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4856 byte_len = (byte_len + 3) & ~3;
4857 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4858 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4859 byte_len += bounds_size;
4862 * Following three lines almost taken from mono_object_new ():
4863 * they need to be kept in sync.
4865 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4866 #ifndef HAVE_SGEN_GC
4867 if (!array_class->has_references) {
4868 o = mono_object_allocate_ptrfree (byte_len, vtable);
4869 #if NEED_TO_ZERO_PTRFREE
4870 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4871 #endif
4872 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4873 o = mono_object_allocate_spec (byte_len, vtable);
4874 }else {
4875 o = mono_object_allocate (byte_len, vtable);
4878 array = (MonoArray*)o;
4879 array->max_length = len;
4881 if (bounds_size) {
4882 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4883 array->bounds = bounds;
4885 #else
4886 if (bounds_size)
4887 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4888 else
4889 o = mono_gc_alloc_vector (vtable, byte_len, len);
4890 array = (MonoArray*)o;
4892 bounds = array->bounds;
4893 #endif
4895 if (bounds_size) {
4896 for (i = 0; i < array_class->rank; ++i) {
4897 bounds [i].length = lengths [i];
4898 if (lower_bounds)
4899 bounds [i].lower_bound = lower_bounds [i];
4903 if (G_UNLIKELY (profile_allocs))
4904 mono_profiler_allocation (o, array_class);
4906 return array;
4910 * mono_array_new:
4911 * @domain: domain where the object is created
4912 * @eclass: element class
4913 * @n: number of array elements
4915 * This routine creates a new szarray with @n elements of type @eclass.
4917 MonoArray *
4918 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4920 MonoClass *ac;
4922 ac = mono_array_class_get (eclass, 1);
4923 g_assert (ac);
4925 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4929 * mono_array_new_specific:
4930 * @vtable: a vtable in the appropriate domain for an initialized class
4931 * @n: number of array elements
4933 * This routine is a fast alternative to mono_array_new() for code which
4934 * can be sure about the domain it operates in.
4936 MonoArray *
4937 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4939 MonoObject *o;
4940 MonoArray *ao;
4941 uintptr_t byte_len;
4943 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4944 arith_overflow ();
4945 return NULL;
4948 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4949 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4950 return NULL;
4952 #ifndef HAVE_SGEN_GC
4953 if (!vtable->klass->has_references) {
4954 o = mono_object_allocate_ptrfree (byte_len, vtable);
4955 #if NEED_TO_ZERO_PTRFREE
4956 ((MonoArray*)o)->bounds = NULL;
4957 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4958 #endif
4959 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4960 o = mono_object_allocate_spec (byte_len, vtable);
4961 } else {
4962 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4963 o = mono_object_allocate (byte_len, vtable);
4966 ao = (MonoArray *)o;
4967 ao->max_length = n;
4968 #else
4969 o = mono_gc_alloc_vector (vtable, byte_len, n);
4970 ao = (MonoArray*)o;
4971 #endif
4973 if (G_UNLIKELY (profile_allocs))
4974 mono_profiler_allocation (o, vtable->klass);
4976 return ao;
4980 * mono_string_new_utf16:
4981 * @text: a pointer to an utf16 string
4982 * @len: the length of the string
4984 * Returns: A newly created string object which contains @text.
4986 MonoString *
4987 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4989 MonoString *s;
4991 s = mono_string_new_size (domain, len);
4992 g_assert (s != NULL);
4994 memcpy (mono_string_chars (s), text, len * 2);
4996 return s;
5000 * mono_string_new_utf32:
5001 * @text: a pointer to an utf32 string
5002 * @len: the length of the string
5004 * Returns: A newly created string object which contains @text.
5006 MonoString *
5007 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5009 MonoString *s;
5010 mono_unichar2 *utf16_output = NULL;
5011 gint32 utf16_len = 0;
5012 GError *error = NULL;
5013 glong items_written;
5015 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &error);
5017 if (error)
5018 g_error_free (error);
5020 while (utf16_output [utf16_len]) utf16_len++;
5022 s = mono_string_new_size (domain, utf16_len);
5023 g_assert (s != NULL);
5025 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5027 g_free (utf16_output);
5029 return s;
5033 * mono_string_new_size:
5034 * @text: a pointer to an utf16 string
5035 * @len: the length of the string
5037 * Returns: A newly created string object of @len
5039 MonoString *
5040 mono_string_new_size (MonoDomain *domain, gint32 len)
5042 MonoString *s;
5043 MonoVTable *vtable;
5044 size_t size;
5046 /* check for overflow */
5047 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2))
5048 mono_gc_out_of_memory (-1);
5050 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5051 g_assert (size > 0);
5053 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5054 g_assert (vtable);
5056 #ifndef HAVE_SGEN_GC
5057 s = mono_object_allocate_ptrfree (size, vtable);
5059 s->length = len;
5060 #else
5061 s = mono_gc_alloc_string (vtable, size, len);
5062 #endif
5063 #if NEED_TO_ZERO_PTRFREE
5064 s->chars [len] = 0;
5065 #endif
5066 if (G_UNLIKELY (profile_allocs))
5067 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
5069 return s;
5073 * mono_string_new_len:
5074 * @text: a pointer to an utf8 string
5075 * @length: number of bytes in @text to consider
5077 * Returns: A newly created string object which contains @text.
5079 MonoString*
5080 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5082 GError *error = NULL;
5083 MonoString *o = NULL;
5084 guint16 *ut;
5085 glong items_written;
5087 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
5089 if (!error)
5090 o = mono_string_new_utf16 (domain, ut, items_written);
5091 else
5092 g_error_free (error);
5094 g_free (ut);
5096 return o;
5100 * mono_string_new:
5101 * @text: a pointer to an utf8 string
5103 * Returns: A newly created string object which contains @text.
5105 MonoString*
5106 mono_string_new (MonoDomain *domain, const char *text)
5108 GError *error = NULL;
5109 MonoString *o = NULL;
5110 guint16 *ut;
5111 glong items_written;
5112 int l;
5114 l = strlen (text);
5116 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
5118 if (!error)
5119 o = mono_string_new_utf16 (domain, ut, items_written);
5120 else
5121 g_error_free (error);
5123 g_free (ut);
5124 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5125 #if 0
5126 gunichar2 *str;
5127 const gchar *end;
5128 int len;
5129 MonoString *o = NULL;
5131 if (!g_utf8_validate (text, -1, &end))
5132 return NULL;
5134 len = g_utf8_strlen (text, -1);
5135 o = mono_string_new_size (domain, len);
5136 str = mono_string_chars (o);
5138 while (text < end) {
5139 *str++ = g_utf8_get_char (text);
5140 text = g_utf8_next_char (text);
5142 #endif
5143 return o;
5147 * mono_string_new_wrapper:
5148 * @text: pointer to utf8 characters.
5150 * Helper function to create a string object from @text in the current domain.
5152 MonoString*
5153 mono_string_new_wrapper (const char *text)
5155 MonoDomain *domain = mono_domain_get ();
5157 if (text)
5158 return mono_string_new (domain, text);
5160 return NULL;
5164 * mono_value_box:
5165 * @class: the class of the value
5166 * @value: a pointer to the unboxed data
5168 * Returns: A newly created object which contains @value.
5170 MonoObject *
5171 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
5173 MonoObject *res;
5174 int size;
5175 MonoVTable *vtable;
5177 g_assert (class->valuetype);
5178 if (mono_class_is_nullable (class))
5179 return mono_nullable_box (value, class);
5181 vtable = mono_class_vtable (domain, class);
5182 if (!vtable)
5183 return NULL;
5184 size = mono_class_instance_size (class);
5185 res = mono_object_new_alloc_specific (vtable);
5186 if (G_UNLIKELY (profile_allocs))
5187 mono_profiler_allocation (res, class);
5189 size = size - sizeof (MonoObject);
5191 #ifdef HAVE_SGEN_GC
5192 g_assert (size == mono_class_value_size (class, NULL));
5193 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
5194 #else
5195 #if NO_UNALIGNED_ACCESS
5196 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5197 #else
5198 switch (size) {
5199 case 1:
5200 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5201 break;
5202 case 2:
5203 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5204 break;
5205 case 4:
5206 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5207 break;
5208 case 8:
5209 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5210 break;
5211 default:
5212 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5214 #endif
5215 #endif
5216 if (class->has_finalize)
5217 mono_object_register_finalizer (res);
5218 return res;
5222 * mono_value_copy:
5223 * @dest: destination pointer
5224 * @src: source pointer
5225 * @klass: a valuetype class
5227 * Copy a valuetype from @src to @dest. This function must be used
5228 * when @klass contains references fields.
5230 void
5231 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5233 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5237 * mono_value_copy_array:
5238 * @dest: destination array
5239 * @dest_idx: index in the @dest array
5240 * @src: source pointer
5241 * @count: number of items
5243 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5244 * This function must be used when @klass contains references fields.
5245 * Overlap is handled.
5247 void
5248 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5250 int size = mono_array_element_size (dest->obj.vtable->klass);
5251 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5252 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5253 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5257 * mono_object_get_domain:
5258 * @obj: object to query
5260 * Returns: the MonoDomain where the object is hosted
5262 MonoDomain*
5263 mono_object_get_domain (MonoObject *obj)
5265 return mono_object_domain (obj);
5269 * mono_object_get_class:
5270 * @obj: object to query
5272 * Returns: the MonOClass of the object.
5274 MonoClass*
5275 mono_object_get_class (MonoObject *obj)
5277 return mono_object_class (obj);
5280 * mono_object_get_size:
5281 * @o: object to query
5283 * Returns: the size, in bytes, of @o
5285 guint
5286 mono_object_get_size (MonoObject* o)
5288 MonoClass* klass = mono_object_class (o);
5289 if (klass == mono_defaults.string_class) {
5290 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5291 } else if (o->vtable->rank) {
5292 MonoArray *array = (MonoArray*)o;
5293 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5294 if (array->bounds) {
5295 size += 3;
5296 size &= ~3;
5297 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5299 return size;
5300 } else {
5301 return mono_class_instance_size (klass);
5306 * mono_object_unbox:
5307 * @obj: object to unbox
5309 * Returns: a pointer to the start of the valuetype boxed in this
5310 * object.
5312 * This method will assert if the object passed is not a valuetype.
5314 gpointer
5315 mono_object_unbox (MonoObject *obj)
5317 /* add assert for valuetypes? */
5318 g_assert (obj->vtable->klass->valuetype);
5319 return ((char*)obj) + sizeof (MonoObject);
5323 * mono_object_isinst:
5324 * @obj: an object
5325 * @klass: a pointer to a class
5327 * Returns: @obj if @obj is derived from @klass
5329 MonoObject *
5330 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5332 if (!klass->inited)
5333 mono_class_init (klass);
5335 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5336 return mono_object_isinst_mbyref (obj, klass);
5338 if (!obj)
5339 return NULL;
5341 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5344 MonoObject *
5345 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5347 MonoVTable *vt;
5349 if (!obj)
5350 return NULL;
5352 vt = obj->vtable;
5354 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5355 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5356 return obj;
5359 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5360 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5361 return obj;
5362 } else {
5363 MonoClass *oklass = vt->klass;
5364 if (mono_class_is_transparent_proxy (oklass))
5365 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5367 mono_class_setup_supertypes (klass);
5368 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5369 return obj;
5371 #ifndef DISABLE_REMOTING
5372 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5374 MonoDomain *domain = mono_domain_get ();
5375 MonoObject *res;
5376 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5377 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5378 MonoMethod *im = NULL;
5379 gpointer pa [2];
5381 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5382 im = mono_object_get_virtual_method (rp, im);
5383 g_assert (im);
5385 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5386 pa [1] = obj;
5388 res = mono_runtime_invoke (im, rp, pa, NULL);
5390 if (*(MonoBoolean *) mono_object_unbox(res)) {
5391 /* Update the vtable of the remote type, so it can safely cast to this new type */
5392 mono_upgrade_remote_class (domain, obj, klass);
5393 return obj;
5396 #endif /* DISABLE_REMOTING */
5397 return NULL;
5401 * mono_object_castclass_mbyref:
5402 * @obj: an object
5403 * @klass: a pointer to a class
5405 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5407 MonoObject *
5408 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5410 if (!obj) return NULL;
5411 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5413 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5414 "System",
5415 "InvalidCastException"));
5416 return NULL;
5419 typedef struct {
5420 MonoDomain *orig_domain;
5421 MonoString *ins;
5422 MonoString *res;
5423 } LDStrInfo;
5425 static void
5426 str_lookup (MonoDomain *domain, gpointer user_data)
5428 LDStrInfo *info = user_data;
5429 if (info->res || domain == info->orig_domain)
5430 return;
5431 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5434 #ifdef HAVE_SGEN_GC
5436 static MonoString*
5437 mono_string_get_pinned (MonoString *str)
5439 int size;
5440 MonoString *news;
5441 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5442 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5443 if (news) {
5444 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5445 news->length = mono_string_length (str);
5447 return news;
5450 #else
5451 #define mono_string_get_pinned(str) (str)
5452 #endif
5454 static MonoString*
5455 mono_string_is_interned_lookup (MonoString *str, int insert)
5457 MonoGHashTable *ldstr_table;
5458 MonoString *s, *res;
5459 MonoDomain *domain;
5461 domain = ((MonoObject *)str)->vtable->domain;
5462 ldstr_table = domain->ldstr_table;
5463 ldstr_lock ();
5464 res = mono_g_hash_table_lookup (ldstr_table, str);
5465 if (res) {
5466 ldstr_unlock ();
5467 return res;
5469 if (insert) {
5470 /* Allocate outside the lock */
5471 ldstr_unlock ();
5472 s = mono_string_get_pinned (str);
5473 if (s) {
5474 ldstr_lock ();
5475 res = mono_g_hash_table_lookup (ldstr_table, str);
5476 if (res) {
5477 ldstr_unlock ();
5478 return res;
5480 mono_g_hash_table_insert (ldstr_table, s, s);
5481 ldstr_unlock ();
5483 return s;
5484 } else {
5485 LDStrInfo ldstr_info;
5486 ldstr_info.orig_domain = domain;
5487 ldstr_info.ins = str;
5488 ldstr_info.res = NULL;
5490 mono_domain_foreach (str_lookup, &ldstr_info);
5491 if (ldstr_info.res) {
5493 * the string was already interned in some other domain:
5494 * intern it in the current one as well.
5496 mono_g_hash_table_insert (ldstr_table, str, str);
5497 ldstr_unlock ();
5498 return str;
5501 ldstr_unlock ();
5502 return NULL;
5506 * mono_string_is_interned:
5507 * @o: String to probe
5509 * Returns whether the string has been interned.
5511 MonoString*
5512 mono_string_is_interned (MonoString *o)
5514 return mono_string_is_interned_lookup (o, FALSE);
5518 * mono_string_intern:
5519 * @o: String to intern
5521 * Interns the string passed.
5522 * Returns: The interned string.
5524 MonoString*
5525 mono_string_intern (MonoString *str)
5527 return mono_string_is_interned_lookup (str, TRUE);
5531 * mono_ldstr:
5532 * @domain: the domain where the string will be used.
5533 * @image: a metadata context
5534 * @idx: index into the user string table.
5536 * Implementation for the ldstr opcode.
5537 * Returns: a loaded string from the @image/@idx combination.
5539 MonoString*
5540 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5542 if (image->dynamic) {
5543 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5544 return str;
5545 } else {
5546 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5547 return NULL; /*FIXME we should probably be raising an exception here*/
5548 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5553 * mono_ldstr_metadata_sig
5554 * @domain: the domain for the string
5555 * @sig: the signature of a metadata string
5557 * Returns: a MonoString for a string stored in the metadata
5559 static MonoString*
5560 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5562 const char *str = sig;
5563 MonoString *o, *interned;
5564 size_t len2;
5566 len2 = mono_metadata_decode_blob_size (str, &str);
5567 len2 >>= 1;
5569 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5570 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5572 int i;
5573 guint16 *p2 = (guint16*)mono_string_chars (o);
5574 for (i = 0; i < len2; ++i) {
5575 *p2 = GUINT16_FROM_LE (*p2);
5576 ++p2;
5579 #endif
5580 ldstr_lock ();
5581 interned = mono_g_hash_table_lookup (domain->ldstr_table, o);
5582 ldstr_unlock ();
5583 if (interned)
5584 return interned; /* o will get garbage collected */
5586 o = mono_string_get_pinned (o);
5587 if (o) {
5588 ldstr_lock ();
5589 interned = mono_g_hash_table_lookup (domain->ldstr_table, o);
5590 if (!interned) {
5591 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5592 interned = o;
5594 ldstr_unlock ();
5597 return interned;
5601 * mono_string_to_utf8:
5602 * @s: a System.String
5604 * Returns the UTF8 representation for @s.
5605 * The resulting buffer needs to be freed with mono_free().
5607 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5609 char *
5610 mono_string_to_utf8 (MonoString *s)
5612 MonoError error;
5613 char *result = mono_string_to_utf8_checked (s, &error);
5615 if (!mono_error_ok (&error))
5616 mono_error_raise_exception (&error);
5617 return result;
5621 * mono_string_to_utf8_checked:
5622 * @s: a System.String
5623 * @error: a MonoError.
5625 * Converts a MonoString to its UTF8 representation. May fail; check
5626 * @error to determine whether the conversion was successful.
5627 * The resulting buffer should be freed with mono_free().
5629 char *
5630 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5632 long written = 0;
5633 char *as;
5634 GError *gerror = NULL;
5636 mono_error_init (error);
5638 if (s == NULL)
5639 return NULL;
5641 if (!s->length)
5642 return g_strdup ("");
5644 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5645 if (gerror) {
5646 mono_error_set_argument (error, "string", "%s", gerror->message);
5647 g_error_free (gerror);
5648 return NULL;
5650 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5651 if (s->length > written) {
5652 /* allocate the total length and copy the part of the string that has been converted */
5653 char *as2 = g_malloc0 (s->length);
5654 memcpy (as2, as, written);
5655 g_free (as);
5656 as = as2;
5659 return as;
5663 * mono_string_to_utf8_ignore:
5664 * @s: a MonoString
5666 * Converts a MonoString to its UTF8 representation. Will ignore
5667 * invalid surrogate pairs.
5668 * The resulting buffer should be freed with mono_free().
5671 char *
5672 mono_string_to_utf8_ignore (MonoString *s)
5674 long written = 0;
5675 char *as;
5677 if (s == NULL)
5678 return NULL;
5680 if (!s->length)
5681 return g_strdup ("");
5683 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5685 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5686 if (s->length > written) {
5687 /* allocate the total length and copy the part of the string that has been converted */
5688 char *as2 = g_malloc0 (s->length);
5689 memcpy (as2, as, written);
5690 g_free (as);
5691 as = as2;
5694 return as;
5698 * mono_string_to_utf8_image_ignore:
5699 * @s: a System.String
5701 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5703 char *
5704 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5706 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5710 * mono_string_to_utf8_mp_ignore:
5711 * @s: a System.String
5713 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5715 char *
5716 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5718 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5723 * mono_string_to_utf16:
5724 * @s: a MonoString
5726 * Return an null-terminated array of the utf-16 chars
5727 * contained in @s. The result must be freed with g_free().
5728 * This is a temporary helper until our string implementation
5729 * is reworked to always include the null terminating char.
5731 mono_unichar2*
5732 mono_string_to_utf16 (MonoString *s)
5734 char *as;
5736 if (s == NULL)
5737 return NULL;
5739 as = g_malloc ((s->length * 2) + 2);
5740 as [(s->length * 2)] = '\0';
5741 as [(s->length * 2) + 1] = '\0';
5743 if (!s->length) {
5744 return (gunichar2 *)(as);
5747 memcpy (as, mono_string_chars(s), s->length * 2);
5748 return (gunichar2 *)(as);
5752 * mono_string_to_utf32:
5753 * @s: a MonoString
5755 * Return an null-terminated array of the UTF-32 (UCS-4) chars
5756 * contained in @s. The result must be freed with g_free().
5758 mono_unichar4*
5759 mono_string_to_utf32 (MonoString *s)
5761 mono_unichar4 *utf32_output = NULL;
5762 GError *error = NULL;
5763 glong items_written;
5765 if (s == NULL)
5766 return NULL;
5768 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
5770 if (error)
5771 g_error_free (error);
5773 return utf32_output;
5777 * mono_string_from_utf16:
5778 * @data: the UTF16 string (LPWSTR) to convert
5780 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5782 * Returns: a MonoString.
5784 MonoString *
5785 mono_string_from_utf16 (gunichar2 *data)
5787 MonoDomain *domain = mono_domain_get ();
5788 int len = 0;
5790 if (!data)
5791 return NULL;
5793 while (data [len]) len++;
5795 return mono_string_new_utf16 (domain, data, len);
5799 * mono_string_from_utf32:
5800 * @data: the UTF32 string (LPWSTR) to convert
5802 * Converts a UTF32 (UCS-4)to a MonoString.
5804 * Returns: a MonoString.
5806 MonoString *
5807 mono_string_from_utf32 (mono_unichar4 *data)
5809 MonoString* result = NULL;
5810 mono_unichar2 *utf16_output = NULL;
5811 GError *error = NULL;
5812 glong items_written;
5813 int len = 0;
5815 if (!data)
5816 return NULL;
5818 while (data [len]) len++;
5820 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
5822 if (error)
5823 g_error_free (error);
5825 result = mono_string_from_utf16 (utf16_output);
5826 g_free (utf16_output);
5827 return result;
5830 static char *
5831 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5833 char *r;
5834 char *mp_s;
5835 int len;
5837 if (ignore_error) {
5838 r = mono_string_to_utf8_ignore (s);
5839 } else {
5840 r = mono_string_to_utf8_checked (s, error);
5841 if (!mono_error_ok (error))
5842 return NULL;
5845 if (!mp && !image)
5846 return r;
5848 len = strlen (r) + 1;
5849 if (mp)
5850 mp_s = mono_mempool_alloc (mp, len);
5851 else
5852 mp_s = mono_image_alloc (image, len);
5854 memcpy (mp_s, r, len);
5856 g_free (r);
5858 return mp_s;
5862 * mono_string_to_utf8_image:
5863 * @s: a System.String
5865 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5867 char *
5868 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5870 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5874 * mono_string_to_utf8_mp:
5875 * @s: a System.String
5877 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5879 char *
5880 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5882 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5886 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
5888 void
5889 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
5891 eh_callbacks = *cbs;
5894 MonoRuntimeExceptionHandlingCallbacks *
5895 mono_get_eh_callbacks (void)
5897 return &eh_callbacks;
5901 * mono_raise_exception:
5902 * @ex: exception object
5904 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5906 void
5907 mono_raise_exception (MonoException *ex)
5910 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5911 * that will cause gcc to omit the function epilog, causing problems when
5912 * the JIT tries to walk the stack, since the return address on the stack
5913 * will point into the next function in the executable, not this one.
5915 eh_callbacks.mono_raise_exception (ex);
5918 void
5919 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
5921 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
5925 * mono_wait_handle_new:
5926 * @domain: Domain where the object will be created
5927 * @handle: Handle for the wait handle
5929 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5931 MonoWaitHandle *
5932 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5934 MonoWaitHandle *res;
5935 gpointer params [1];
5936 static MonoMethod *handle_set;
5938 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5940 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5941 if (!handle_set)
5942 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5944 params [0] = &handle;
5945 mono_runtime_invoke (handle_set, res, params, NULL);
5947 return res;
5950 HANDLE
5951 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5953 static MonoClassField *f_os_handle;
5954 static MonoClassField *f_safe_handle;
5956 if (!f_os_handle && !f_safe_handle) {
5957 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5958 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5961 if (f_os_handle) {
5962 HANDLE retval;
5963 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5964 return retval;
5965 } else {
5966 MonoSafeHandle *sh;
5967 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5968 return sh->handle;
5973 static MonoObject*
5974 mono_runtime_capture_context (MonoDomain *domain)
5976 RuntimeInvokeFunction runtime_invoke;
5978 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5979 MonoMethod *method = mono_get_context_capture_method ();
5980 MonoMethod *wrapper;
5981 if (!method)
5982 return NULL;
5983 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5984 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5985 domain->capture_context_method = mono_compile_method (method);
5988 runtime_invoke = domain->capture_context_runtime_invoke;
5990 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5993 * mono_async_result_new:
5994 * @domain:domain where the object will be created.
5995 * @handle: wait handle.
5996 * @state: state to pass to AsyncResult
5997 * @data: C closure data.
5999 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6000 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6003 MonoAsyncResult *
6004 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6006 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
6007 MonoObject *context = mono_runtime_capture_context (domain);
6008 /* we must capture the execution context from the original thread */
6009 if (context) {
6010 MONO_OBJECT_SETREF (res, execution_context, context);
6011 /* note: result may be null if the flow is suppressed */
6014 res->data = data;
6015 MONO_OBJECT_SETREF (res, object_data, object_data);
6016 MONO_OBJECT_SETREF (res, async_state, state);
6017 if (handle != NULL)
6018 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6020 res->sync_completed = FALSE;
6021 res->completed = FALSE;
6023 return res;
6026 void
6027 mono_message_init (MonoDomain *domain,
6028 MonoMethodMessage *this,
6029 MonoReflectionMethod *method,
6030 MonoArray *out_args)
6032 static MonoClass *object_array_klass;
6033 static MonoClass *byte_array_klass;
6034 static MonoClass *string_array_klass;
6035 MonoMethodSignature *sig = mono_method_signature (method->method);
6036 MonoString *name;
6037 int i, j;
6038 char **names;
6039 guint8 arg_type;
6041 if (!object_array_klass) {
6042 MonoClass *klass;
6044 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6045 g_assert (klass);
6046 byte_array_klass = klass;
6048 klass = mono_array_class_get (mono_defaults.string_class, 1);
6049 g_assert (klass);
6050 string_array_klass = klass;
6052 klass = mono_array_class_get (mono_defaults.object_class, 1);
6053 g_assert (klass);
6055 mono_atomic_store_release (&object_array_klass, klass);
6058 MONO_OBJECT_SETREF (this, method, method);
6060 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
6061 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
6062 this->async_result = NULL;
6063 this->call_type = CallType_Sync;
6065 names = g_new (char *, sig->param_count);
6066 mono_method_get_param_names (method->method, (const char **) names);
6067 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
6069 for (i = 0; i < sig->param_count; i++) {
6070 name = mono_string_new (domain, names [i]);
6071 mono_array_setref (this->names, i, name);
6074 g_free (names);
6075 for (i = 0, j = 0; i < sig->param_count; i++) {
6076 if (sig->params [i]->byref) {
6077 if (out_args) {
6078 MonoObject* arg = mono_array_get (out_args, gpointer, j);
6079 mono_array_setref (this->args, i, arg);
6080 j++;
6082 arg_type = 2;
6083 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6084 arg_type |= 1;
6085 } else {
6086 arg_type = 1;
6087 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6088 arg_type |= 4;
6090 mono_array_set (this->arg_types, guint8, i, arg_type);
6094 #ifndef DISABLE_REMOTING
6096 * mono_remoting_invoke:
6097 * @real_proxy: pointer to a RealProxy object
6098 * @msg: The MonoMethodMessage to execute
6099 * @exc: used to store exceptions
6100 * @out_args: used to store output arguments
6102 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6103 * IMessage interface and it is not trivial to extract results from there. So
6104 * we call an helper method PrivateInvoke instead of calling
6105 * RealProxy::Invoke() directly.
6107 * Returns: the result object.
6109 MonoObject *
6110 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
6111 MonoObject **exc, MonoArray **out_args)
6113 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6114 gpointer pa [4];
6116 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6118 if (!im) {
6119 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6120 g_assert (im);
6121 real_proxy->vtable->domain->private_invoke_method = im;
6124 pa [0] = real_proxy;
6125 pa [1] = msg;
6126 pa [2] = exc;
6127 pa [3] = out_args;
6129 return mono_runtime_invoke (im, NULL, pa, exc);
6131 #endif
6133 MonoObject *
6134 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6135 MonoObject **exc, MonoArray **out_args)
6137 static MonoClass *object_array_klass;
6138 MonoDomain *domain;
6139 MonoMethod *method;
6140 MonoMethodSignature *sig;
6141 MonoObject *ret;
6142 int i, j, outarg_count = 0;
6144 #ifndef DISABLE_REMOTING
6145 if (target && mono_object_is_transparent_proxy (target)) {
6146 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6147 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6148 target = tp->rp->unwrapped_server;
6149 } else {
6150 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6153 #endif
6155 domain = mono_domain_get ();
6156 method = msg->method->method;
6157 sig = mono_method_signature (method);
6159 for (i = 0; i < sig->param_count; i++) {
6160 if (sig->params [i]->byref)
6161 outarg_count++;
6164 if (!object_array_klass) {
6165 MonoClass *klass;
6167 klass = mono_array_class_get (mono_defaults.object_class, 1);
6168 g_assert (klass);
6170 mono_memory_barrier ();
6171 object_array_klass = klass;
6174 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
6175 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
6176 *exc = NULL;
6178 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6180 for (i = 0, j = 0; i < sig->param_count; i++) {
6181 if (sig->params [i]->byref) {
6182 MonoObject* arg;
6183 arg = mono_array_get (msg->args, gpointer, i);
6184 mono_array_setref (*out_args, j, arg);
6185 j++;
6189 return ret;
6193 * mono_object_to_string:
6194 * @obj: The object
6195 * @exc: Any exception thrown by ToString (). May be NULL.
6197 * Returns: the result of calling ToString () on an object.
6199 MonoString *
6200 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6202 static MonoMethod *to_string = NULL;
6203 MonoMethod *method;
6204 void *target = obj;
6206 g_assert (obj);
6208 if (!to_string)
6209 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6211 method = mono_object_get_virtual_method (obj, to_string);
6213 // Unbox value type if needed
6214 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6215 target = mono_object_unbox (obj);
6218 return (MonoString *) mono_runtime_invoke (method, target, NULL, exc);
6222 * mono_print_unhandled_exception:
6223 * @exc: The exception
6225 * Prints the unhandled exception.
6227 void
6228 mono_print_unhandled_exception (MonoObject *exc)
6230 MonoString * str;
6231 char *message = (char*)"";
6232 gboolean free_message = FALSE;
6233 MonoError error;
6235 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6236 message = g_strdup ("OutOfMemoryException");
6237 free_message = TRUE;
6238 } else {
6240 if (((MonoException*)exc)->native_trace_ips) {
6241 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6242 free_message = TRUE;
6243 } else {
6244 MonoObject *other_exc = NULL;
6245 str = mono_object_to_string (exc, &other_exc);
6246 if (other_exc) {
6247 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6248 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6250 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6251 original_backtrace, nested_backtrace);
6253 g_free (original_backtrace);
6254 g_free (nested_backtrace);
6255 free_message = TRUE;
6256 } else if (str) {
6257 message = mono_string_to_utf8_checked (str, &error);
6258 if (!mono_error_ok (&error)) {
6259 mono_error_cleanup (&error);
6260 message = (char *) "";
6261 } else {
6262 free_message = TRUE;
6269 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
6270 * exc->vtable->klass->name, message);
6272 g_printerr ("\nUnhandled Exception:\n%s\n", message);
6274 if (free_message)
6275 g_free (message);
6279 * mono_delegate_ctor:
6280 * @this: pointer to an uninitialized delegate object
6281 * @target: target object
6282 * @addr: pointer to native code
6283 * @method: method
6285 * Initialize a delegate and sets a specific method, not the one
6286 * associated with addr. This is useful when sharing generic code.
6287 * In that case addr will most probably not be associated with the
6288 * correct instantiation of the method.
6290 void
6291 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
6293 MonoDelegate *delegate = (MonoDelegate *)this;
6295 g_assert (this);
6296 g_assert (addr);
6298 if (method)
6299 delegate->method = method;
6301 mono_stats.delegate_creations++;
6303 #ifndef DISABLE_REMOTING
6304 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6305 g_assert (method);
6306 method = mono_marshal_get_remoting_invoke (method);
6307 delegate->method_ptr = mono_compile_method (method);
6308 MONO_OBJECT_SETREF (delegate, target, target);
6309 } else
6310 #endif
6312 delegate->method_ptr = addr;
6313 MONO_OBJECT_SETREF (delegate, target, target);
6316 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6320 * mono_delegate_ctor:
6321 * @this: pointer to an uninitialized delegate object
6322 * @target: target object
6323 * @addr: pointer to native code
6325 * This is used to initialize a delegate.
6327 void
6328 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
6330 MonoDomain *domain = mono_domain_get ();
6331 MonoJitInfo *ji;
6332 MonoMethod *method = NULL;
6334 g_assert (addr);
6336 ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr));
6337 /* Shared code */
6338 if (!ji && domain != mono_get_root_domain ())
6339 ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr));
6340 if (ji) {
6341 method = mono_jit_info_get_method (ji);
6342 g_assert (!method->klass->generic_container);
6345 mono_delegate_ctor_with_method (this, target, addr, method);
6349 * mono_method_call_message_new:
6350 * @method: method to encapsulate
6351 * @params: parameters to the method
6352 * @invoke: optional, delegate invoke.
6353 * @cb: async callback delegate.
6354 * @state: state passed to the async callback.
6356 * Translates arguments pointers into a MonoMethodMessage.
6358 MonoMethodMessage *
6359 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6360 MonoDelegate **cb, MonoObject **state)
6362 MonoDomain *domain = mono_domain_get ();
6363 MonoMethodSignature *sig = mono_method_signature (method);
6364 MonoMethodMessage *msg;
6365 int i, count;
6367 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6369 if (invoke) {
6370 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6371 count = sig->param_count - 2;
6372 } else {
6373 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6374 count = sig->param_count;
6377 for (i = 0; i < count; i++) {
6378 gpointer vpos;
6379 MonoClass *class;
6380 MonoObject *arg;
6382 if (sig->params [i]->byref)
6383 vpos = *((gpointer *)params [i]);
6384 else
6385 vpos = params [i];
6387 class = mono_class_from_mono_type (sig->params [i]);
6389 if (class->valuetype)
6390 arg = mono_value_box (domain, class, vpos);
6391 else
6392 arg = *((MonoObject **)vpos);
6394 mono_array_setref (msg->args, i, arg);
6397 if (cb != NULL && state != NULL) {
6398 *cb = *((MonoDelegate **)params [i]);
6399 i++;
6400 *state = *((MonoObject **)params [i]);
6403 return msg;
6407 * mono_method_return_message_restore:
6409 * Restore results from message based processing back to arguments pointers
6411 void
6412 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6414 MonoMethodSignature *sig = mono_method_signature (method);
6415 int i, j, type, size, out_len;
6417 if (out_args == NULL)
6418 return;
6419 out_len = mono_array_length (out_args);
6420 if (out_len == 0)
6421 return;
6423 for (i = 0, j = 0; i < sig->param_count; i++) {
6424 MonoType *pt = sig->params [i];
6426 if (pt->byref) {
6427 char *arg;
6428 if (j >= out_len)
6429 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6431 arg = mono_array_get (out_args, gpointer, j);
6432 type = pt->type;
6434 g_assert (type != MONO_TYPE_VOID);
6436 if (MONO_TYPE_IS_REFERENCE (pt)) {
6437 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6438 } else {
6439 if (arg) {
6440 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6441 size = mono_class_value_size (class, NULL);
6442 if (class->has_references)
6443 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6444 else
6445 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6446 } else {
6447 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6448 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
6452 j++;
6457 #ifndef DISABLE_REMOTING
6460 * mono_load_remote_field:
6461 * @this: pointer to an object
6462 * @klass: klass of the object containing @field
6463 * @field: the field to load
6464 * @res: a storage to store the result
6466 * This method is called by the runtime on attempts to load fields of
6467 * transparent proxy objects. @this points to such TP, @klass is the class of
6468 * the object containing @field. @res is a storage location which can be
6469 * used to store the result.
6471 * Returns: an address pointing to the value of field.
6473 gpointer
6474 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6476 static MonoMethod *getter = NULL;
6477 MonoDomain *domain = mono_domain_get ();
6478 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6479 MonoClass *field_class;
6480 MonoMethodMessage *msg;
6481 MonoArray *out_args;
6482 MonoObject *exc;
6483 char* full_name;
6485 g_assert (mono_object_is_transparent_proxy (this));
6486 g_assert (res != NULL);
6488 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6489 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6490 return res;
6493 if (!getter) {
6494 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6495 g_assert (getter);
6498 field_class = mono_class_from_mono_type (field->type);
6500 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6501 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6502 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6504 full_name = mono_type_get_full_name (klass);
6505 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6506 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6507 g_free (full_name);
6509 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6511 if (exc) mono_raise_exception ((MonoException *)exc);
6513 if (mono_array_length (out_args) == 0)
6514 return NULL;
6516 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6518 if (field_class->valuetype) {
6519 return ((char *)*res) + sizeof (MonoObject);
6520 } else
6521 return res;
6525 * mono_load_remote_field_new:
6526 * @this:
6527 * @klass:
6528 * @field:
6530 * Missing documentation.
6532 MonoObject *
6533 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6535 static MonoMethod *getter = NULL;
6536 MonoDomain *domain = mono_domain_get ();
6537 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6538 MonoClass *field_class;
6539 MonoMethodMessage *msg;
6540 MonoArray *out_args;
6541 MonoObject *exc, *res;
6542 char* full_name;
6544 g_assert (mono_object_is_transparent_proxy (this));
6546 field_class = mono_class_from_mono_type (field->type);
6548 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6549 gpointer val;
6550 if (field_class->valuetype) {
6551 res = mono_object_new (domain, field_class);
6552 val = ((gchar *) res) + sizeof (MonoObject);
6553 } else {
6554 val = &res;
6556 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6557 return res;
6560 if (!getter) {
6561 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6562 g_assert (getter);
6565 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6566 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6568 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6570 full_name = mono_type_get_full_name (klass);
6571 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6572 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6573 g_free (full_name);
6575 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6577 if (exc) mono_raise_exception ((MonoException *)exc);
6579 if (mono_array_length (out_args) == 0)
6580 res = NULL;
6581 else
6582 res = mono_array_get (out_args, MonoObject *, 0);
6584 return res;
6588 * mono_store_remote_field:
6589 * @this: pointer to an object
6590 * @klass: klass of the object containing @field
6591 * @field: the field to load
6592 * @val: the value/object to store
6594 * This method is called by the runtime on attempts to store fields of
6595 * transparent proxy objects. @this points to such TP, @klass is the class of
6596 * the object containing @field. @val is the new value to store in @field.
6598 void
6599 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6601 static MonoMethod *setter = NULL;
6602 MonoDomain *domain = mono_domain_get ();
6603 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6604 MonoClass *field_class;
6605 MonoMethodMessage *msg;
6606 MonoArray *out_args;
6607 MonoObject *exc;
6608 MonoObject *arg;
6609 char* full_name;
6611 g_assert (mono_object_is_transparent_proxy (this));
6613 field_class = mono_class_from_mono_type (field->type);
6615 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6616 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6617 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6618 return;
6621 if (!setter) {
6622 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6623 g_assert (setter);
6626 if (field_class->valuetype)
6627 arg = mono_value_box (domain, field_class, val);
6628 else
6629 arg = *((MonoObject **)val);
6632 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6633 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6635 full_name = mono_type_get_full_name (klass);
6636 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6637 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6638 mono_array_setref (msg->args, 2, arg);
6639 g_free (full_name);
6641 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6643 if (exc) mono_raise_exception ((MonoException *)exc);
6647 * mono_store_remote_field_new:
6648 * @this:
6649 * @klass:
6650 * @field:
6651 * @arg:
6653 * Missing documentation
6655 void
6656 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6658 static MonoMethod *setter = NULL;
6659 MonoDomain *domain = mono_domain_get ();
6660 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6661 MonoClass *field_class;
6662 MonoMethodMessage *msg;
6663 MonoArray *out_args;
6664 MonoObject *exc;
6665 char* full_name;
6667 g_assert (mono_object_is_transparent_proxy (this));
6669 field_class = mono_class_from_mono_type (field->type);
6671 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6672 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6673 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6674 return;
6677 if (!setter) {
6678 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6679 g_assert (setter);
6682 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6683 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6685 full_name = mono_type_get_full_name (klass);
6686 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6687 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6688 mono_array_setref (msg->args, 2, arg);
6689 g_free (full_name);
6691 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6693 if (exc) mono_raise_exception ((MonoException *)exc);
6695 #endif
6698 * mono_create_ftnptr:
6700 * Given a function address, create a function descriptor for it.
6701 * This is only needed on some platforms.
6703 gpointer
6704 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6706 return callbacks.create_ftnptr (domain, addr);
6710 * mono_get_addr_from_ftnptr:
6712 * Given a pointer to a function descriptor, return the function address.
6713 * This is only needed on some platforms.
6715 gpointer
6716 mono_get_addr_from_ftnptr (gpointer descr)
6718 return callbacks.get_addr_from_ftnptr (descr);
6722 * mono_string_chars:
6723 * @s: a MonoString
6725 * Returns a pointer to the UCS16 characters stored in the MonoString
6727 gunichar2 *
6728 mono_string_chars (MonoString *s)
6730 return s->chars;
6734 * mono_string_length:
6735 * @s: MonoString
6737 * Returns the lenght in characters of the string
6740 mono_string_length (MonoString *s)
6742 return s->length;
6746 * mono_array_length:
6747 * @array: a MonoArray*
6749 * Returns the total number of elements in the array. This works for
6750 * both vectors and multidimensional arrays.
6752 uintptr_t
6753 mono_array_length (MonoArray *array)
6755 return array->max_length;
6759 * mono_array_addr_with_size:
6760 * @array: a MonoArray*
6761 * @size: size of the array elements
6762 * @idx: index into the array
6764 * Returns the address of the @idx element in the array.
6766 char*
6767 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6769 return ((char*)(array)->vector) + size * idx;