2 * domain.c: MonoDomain functions
5 * Dietmar Maurer (dietmar@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
10 * Copyright 2011-2012 Xamarin, Inc (http://www.xamarin.com)
18 #include <mono/metadata/gc-internal.h>
20 #include <mono/utils/atomic.h>
21 #include <mono/utils/mono-compiler.h>
22 #include <mono/utils/mono-logger-internal.h>
23 #include <mono/utils/mono-membar.h>
24 #include <mono/utils/mono-counters.h>
25 #include <mono/utils/hazard-pointer.h>
26 #include <mono/utils/mono-tls.h>
27 #include <mono/utils/mono-mmap.h>
28 #include <mono/utils/mono-threads.h>
29 #include <mono/metadata/object.h>
30 #include <mono/metadata/object-internals.h>
31 #include <mono/metadata/domain-internals.h>
32 #include <mono/metadata/class-internals.h>
33 #include <mono/metadata/assembly.h>
34 #include <mono/metadata/exception.h>
35 #include <mono/metadata/metadata-internals.h>
36 #include <mono/metadata/gc-internal.h>
37 #include <mono/metadata/appdomain.h>
38 #include <mono/metadata/mono-debug-debugger.h>
39 #include <mono/metadata/mono-config.h>
40 #include <mono/metadata/threads-types.h>
41 #include <mono/metadata/runtime.h>
42 #include <metadata/threads.h>
43 #include <metadata/profiler-private.h>
44 #include <mono/metadata/coree.h>
46 //#define DEBUG_DOMAIN_UNLOAD 1
48 /* we need to use both the Tls* functions and __thread because
49 * some archs may generate faster jit code with one meachanism
50 * or the other (we used to do it because tls slots were GC-tracked,
51 * but we can't depend on this).
53 static MonoNativeTlsKey appdomain_thread_id;
55 #ifdef MONO_HAVE_FAST_TLS
57 MONO_FAST_TLS_DECLARE(tls_appdomain);
59 #define GET_APPDOMAIN() ((MonoDomain*)MONO_FAST_TLS_GET(tls_appdomain))
61 #define SET_APPDOMAIN(x) do { \
62 MonoThreadInfo *info; \
63 MONO_FAST_TLS_SET (tls_appdomain,x); \
64 mono_native_tls_set_value (appdomain_thread_id, x); \
65 mono_gc_set_current_thread_appdomain (x); \
66 info = mono_thread_info_current (); \
68 mono_thread_info_tls_set (info, TLS_KEY_DOMAIN, (x)); \
71 #else /* !MONO_HAVE_FAST_TLS */
73 #define GET_APPDOMAIN() ((MonoDomain *)mono_native_tls_get_value (appdomain_thread_id))
74 #define SET_APPDOMAIN(x) do { \
75 MonoThreadInfo *info; \
76 mono_native_tls_set_value (appdomain_thread_id, x); \
77 mono_gc_set_current_thread_appdomain (x); \
78 info = mono_thread_info_current (); \
80 mono_thread_info_tls_set (info, TLS_KEY_DOMAIN, (x)); \
85 #define GET_APPCONTEXT() (mono_thread_internal_current ()->current_appcontext)
86 #define SET_APPCONTEXT(x) MONO_OBJECT_SETREF (mono_thread_internal_current (), current_appcontext, (x))
88 static guint16 appdomain_list_size = 0;
89 static guint16 appdomain_next = 0;
90 static MonoDomain **appdomains_list = NULL;
91 static MonoImage *exe_image;
92 static gboolean debug_domain_unload;
94 gboolean mono_dont_free_domains;
96 #define mono_appdomains_lock() mono_mutex_lock (&appdomains_mutex)
97 #define mono_appdomains_unlock() mono_mutex_unlock (&appdomains_mutex)
98 static mono_mutex_t appdomains_mutex;
100 static MonoDomain *mono_root_domain = NULL;
102 /* some statistics */
103 static int max_domain_code_size = 0;
104 static int max_domain_code_alloc = 0;
105 static int total_domain_code_alloc = 0;
107 /* AppConfigInfo: Information about runtime versions supported by an
111 GSList *supported_runtimes;
112 char *required_runtime;
113 int configuration_count;
117 static const MonoRuntimeInfo *current_runtime = NULL;
119 static MonoJitInfoFindInAot jit_info_find_in_aot_func = NULL;
121 /* This is the list of runtime versions supported by this JIT.
123 static const MonoRuntimeInfo supported_runtimes[] = {
124 {"v2.0.50215","2.0", { {2,0,0,0}, { 8,0,0,0}, {3,5,0,0}, {3,0,0,0} } },
125 {"v2.0.50727","2.0", { {2,0,0,0}, { 8,0,0,0}, {3,5,0,0}, {3,0,0,0} } },
126 {"v4.0.30319","4.5", { {4,0,0,0}, {10,0,0,0}, {4,0,0,0}, {4,0,0,0} } },
127 {"v4.0.30128","4.0", { {4,0,0,0}, {10,0,0,0}, {4,0,0,0}, {4,0,0,0} } },
128 {"v4.0.20506","4.0", { {4,0,0,0}, {10,0,0,0}, {4,0,0,0}, {4,0,0,0} } },
129 {"mobile", "2.1", { {2,0,5,0}, {10,0,0,0}, {2,0,5,0}, {2,0,5,0} } },
130 {"moonlight", "2.1", { {2,0,5,0}, { 9,0,0,0}, {3,5,0,0}, {3,0,0,0} } },
134 /* The stable runtime version */
135 #define DEFAULT_RUNTIME_VERSION "v2.0.50727"
137 /* Callbacks installed by the JIT */
138 static MonoCreateDomainFunc create_domain_hook;
139 static MonoFreeDomainFunc free_domain_hook;
141 /* AOT cache configuration */
142 static MonoAotCacheConfig aot_cache_config;
144 /* This is intentionally not in the header file, so people don't misuse it. */
145 extern void _mono_debug_init_corlib (MonoDomain *domain);
148 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes);
150 static const MonoRuntimeInfo*
151 get_runtime_by_version (const char *version);
154 mono_domain_get_tls_key (void)
156 return appdomain_thread_id;
160 mono_domain_get_tls_offset (void)
165 if (appdomain_thread_id)
166 offset = appdomain_thread_id;
168 MONO_THREAD_VAR_OFFSET (tls_appdomain, offset);
173 #define JIT_INFO_TABLE_FILL_RATIO_NOM 3
174 #define JIT_INFO_TABLE_FILL_RATIO_DENOM 4
175 #define JIT_INFO_TABLE_FILLED_NUM_ELEMENTS (MONO_JIT_INFO_TABLE_CHUNK_SIZE * JIT_INFO_TABLE_FILL_RATIO_NOM / JIT_INFO_TABLE_FILL_RATIO_DENOM)
177 #define JIT_INFO_TABLE_LOW_WATERMARK(n) ((n) / 2)
178 #define JIT_INFO_TABLE_HIGH_WATERMARK(n) ((n) * 5 / 6)
180 #define JIT_INFO_TOMBSTONE_MARKER ((MonoMethod*)NULL)
181 #define IS_JIT_INFO_TOMBSTONE(ji) ((ji)->d.method == JIT_INFO_TOMBSTONE_MARKER)
183 #define JIT_INFO_TABLE_HAZARD_INDEX 0
184 #define JIT_INFO_HAZARD_INDEX 1
187 jit_info_table_num_elements (MonoJitInfoTable *table)
190 int num_elements = 0;
192 for (i = 0; i < table->num_chunks; ++i) {
193 MonoJitInfoTableChunk *chunk = table->chunks [i];
194 int chunk_num_elements = chunk->num_elements;
197 for (j = 0; j < chunk_num_elements; ++j) {
198 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j]))
206 static MonoJitInfoTableChunk*
207 jit_info_table_new_chunk (void)
209 MonoJitInfoTableChunk *chunk = g_new0 (MonoJitInfoTableChunk, 1);
215 static MonoJitInfoTable *
216 jit_info_table_new (MonoDomain *domain)
218 MonoJitInfoTable *table = g_malloc0 (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*));
220 table->domain = domain;
221 table->num_chunks = 1;
222 table->chunks [0] = jit_info_table_new_chunk ();
228 jit_info_table_free (MonoJitInfoTable *table)
231 int num_chunks = table->num_chunks;
232 MonoDomain *domain = table->domain;
234 mono_domain_lock (domain);
236 table->domain->num_jit_info_tables--;
237 if (table->domain->num_jit_info_tables <= 1) {
240 for (list = table->domain->jit_info_free_queue; list; list = list->next)
243 g_slist_free (table->domain->jit_info_free_queue);
244 table->domain->jit_info_free_queue = NULL;
247 /* At this point we assume that there are no other threads
248 still accessing the table, so we don't have to worry about
249 hazardous pointers. */
251 for (i = 0; i < num_chunks; ++i) {
252 MonoJitInfoTableChunk *chunk = table->chunks [i];
256 if (--chunk->refcount > 0)
259 num_elements = chunk->num_elements;
260 for (j = 0; j < num_elements; ++j) {
261 MonoJitInfo *ji = chunk->data [j];
263 if (IS_JIT_INFO_TOMBSTONE (ji))
270 mono_domain_unlock (domain);
275 /* The jit_info_table is sorted in ascending order by the end
276 * addresses of the compiled methods. The reason why we have to do
277 * this is that once we introduce tombstones, it becomes possible for
278 * code ranges to overlap, and if we sort by code start and insert at
279 * the back of the table, we cannot guarantee that we won't overlook
282 * There are actually two possible ways to do the sorting and
283 * inserting which work with our lock-free mechanism:
285 * 1. Sort by start address and insert at the front. When looking for
286 * an entry, find the last one with a start address lower than the one
287 * you're looking for, then work your way to the front of the table.
289 * 2. Sort by end address and insert at the back. When looking for an
290 * entry, find the first one with an end address higher than the one
291 * you're looking for, then work your way to the end of the table.
293 * We chose the latter out of convenience.
296 jit_info_table_index (MonoJitInfoTable *table, gint8 *addr)
298 int left = 0, right = table->num_chunks;
300 g_assert (left < right);
303 int pos = (left + right) / 2;
304 MonoJitInfoTableChunk *chunk = table->chunks [pos];
306 if (addr < chunk->last_code_end)
310 } while (left < right);
311 g_assert (left == right);
313 if (left >= table->num_chunks)
314 return table->num_chunks - 1;
319 jit_info_table_chunk_index (MonoJitInfoTableChunk *chunk, MonoThreadHazardPointers *hp, gint8 *addr)
321 int left = 0, right = chunk->num_elements;
323 while (left < right) {
324 int pos = (left + right) / 2;
325 MonoJitInfo *ji = get_hazardous_pointer((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
326 gint8 *code_end = (gint8*)ji->code_start + ji->code_size;
333 g_assert (left == right);
339 jit_info_table_find (MonoJitInfoTable *table, MonoThreadHazardPointers *hp, gint8 *addr)
344 chunk_pos = jit_info_table_index (table, (gint8*)addr);
345 g_assert (chunk_pos < table->num_chunks);
347 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], hp, (gint8*)addr);
349 /* We now have a position that's very close to that of the
350 first element whose end address is higher than the one
351 we're looking for. If we don't have the exact position,
352 then we have a position below that one, so we'll just
353 search upward until we find our element. */
355 MonoJitInfoTableChunk *chunk = table->chunks [chunk_pos];
357 while (pos < chunk->num_elements) {
358 ji = get_hazardous_pointer ((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
362 if (IS_JIT_INFO_TOMBSTONE (ji)) {
363 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
366 if ((gint8*)addr >= (gint8*)ji->code_start
367 && (gint8*)addr < (gint8*)ji->code_start + ji->code_size) {
368 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
372 /* If we find a non-tombstone element which is already
373 beyond what we're looking for, we have to end the
375 if ((gint8*)addr < (gint8*)ji->code_start)
381 } while (chunk_pos < table->num_chunks);
385 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
390 * mono_jit_info_table_find_internal:
392 * If TRY_AOT is FALSE, avoid loading information for missing methods from AOT images, which is currently not async safe.
393 * In this case, only those AOT methods will be found whose jit info is already loaded.
394 * ASYNC SAFETY: When called in an async context (mono_thread_info_is_async_context ()), this is async safe.
395 * In this case, the returned MonoJitInfo might not have metadata information, in particular,
396 * mono_jit_info_get_method () could fail.
399 mono_jit_info_table_find_internal (MonoDomain *domain, char *addr, gboolean try_aot)
401 MonoJitInfoTable *table;
402 MonoJitInfo *ji, *module_ji;
403 MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
405 ++mono_stats.jit_info_table_lookup_count;
407 /* First we have to get the domain's jit_info_table. This is
408 complicated by the fact that a writer might substitute a
409 new table and free the old one. What the writer guarantees
410 us is that it looks at the hazard pointers after it has
411 changed the jit_info_table pointer. So, if we guard the
412 table by a hazard pointer and make sure that the pointer is
413 still there after we've made it hazardous, we don't have to
414 worry about the writer freeing the table. */
415 table = get_hazardous_pointer ((gpointer volatile*)&domain->jit_info_table, hp, JIT_INFO_TABLE_HAZARD_INDEX);
417 ji = jit_info_table_find (table, hp, (gint8*)addr);
419 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
423 /* Maybe its an AOT module */
424 if (try_aot && mono_root_domain && mono_root_domain->aot_modules) {
425 table = get_hazardous_pointer ((gpointer volatile*)&mono_root_domain->aot_modules, hp, JIT_INFO_TABLE_HAZARD_INDEX);
426 module_ji = jit_info_table_find (table, hp, (gint8*)addr);
428 ji = jit_info_find_in_aot_func (domain, module_ji->d.image, addr);
430 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
437 mono_jit_info_table_find (MonoDomain *domain, char *addr)
439 return mono_jit_info_table_find_internal (domain, addr, TRUE);
442 static G_GNUC_UNUSED void
443 jit_info_table_check (MonoJitInfoTable *table)
447 for (i = 0; i < table->num_chunks; ++i) {
448 MonoJitInfoTableChunk *chunk = table->chunks [i];
451 g_assert (chunk->refcount > 0 /* && chunk->refcount <= 8 */);
452 if (chunk->refcount > 10)
453 printf("warning: chunk refcount is %d\n", chunk->refcount);
454 g_assert (chunk->num_elements <= MONO_JIT_INFO_TABLE_CHUNK_SIZE);
456 for (j = 0; j < chunk->num_elements; ++j) {
457 MonoJitInfo *this = chunk->data [j];
460 g_assert ((gint8*)this->code_start + this->code_size <= chunk->last_code_end);
462 if (j < chunk->num_elements - 1)
463 next = chunk->data [j + 1];
464 else if (i < table->num_chunks - 1) {
467 for (k = i + 1; k < table->num_chunks; ++k)
468 if (table->chunks [k]->num_elements > 0)
471 if (k >= table->num_chunks)
474 g_assert (table->chunks [k]->num_elements > 0);
475 next = table->chunks [k]->data [0];
479 g_assert ((gint8*)this->code_start + this->code_size <= (gint8*)next->code_start + next->code_size);
484 static MonoJitInfoTable*
485 jit_info_table_realloc (MonoJitInfoTable *old)
488 int num_elements = jit_info_table_num_elements (old);
491 int new_chunk, new_element;
492 MonoJitInfoTable *new;
494 /* number of needed places for elements needed */
495 required_size = (int)((long)num_elements * JIT_INFO_TABLE_FILL_RATIO_DENOM / JIT_INFO_TABLE_FILL_RATIO_NOM);
496 num_chunks = (required_size + MONO_JIT_INFO_TABLE_CHUNK_SIZE - 1) / MONO_JIT_INFO_TABLE_CHUNK_SIZE;
497 if (num_chunks == 0) {
498 g_assert (num_elements == 0);
499 return jit_info_table_new (old->domain);
501 g_assert (num_chunks > 0);
503 new = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*) * num_chunks);
504 new->domain = old->domain;
505 new->num_chunks = num_chunks;
507 for (i = 0; i < num_chunks; ++i)
508 new->chunks [i] = jit_info_table_new_chunk ();
512 for (i = 0; i < old->num_chunks; ++i) {
513 MonoJitInfoTableChunk *chunk = old->chunks [i];
514 int chunk_num_elements = chunk->num_elements;
517 for (j = 0; j < chunk_num_elements; ++j) {
518 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j])) {
519 g_assert (new_chunk < num_chunks);
520 new->chunks [new_chunk]->data [new_element] = chunk->data [j];
521 if (++new_element >= JIT_INFO_TABLE_FILLED_NUM_ELEMENTS) {
522 new->chunks [new_chunk]->num_elements = new_element;
530 if (new_chunk < num_chunks) {
531 g_assert (new_chunk == num_chunks - 1);
532 new->chunks [new_chunk]->num_elements = new_element;
533 g_assert (new->chunks [new_chunk]->num_elements > 0);
536 for (i = 0; i < num_chunks; ++i) {
537 MonoJitInfoTableChunk *chunk = new->chunks [i];
538 MonoJitInfo *ji = chunk->data [chunk->num_elements - 1];
540 new->chunks [i]->last_code_end = (gint8*)ji->code_start + ji->code_size;
547 jit_info_table_split_chunk (MonoJitInfoTableChunk *chunk, MonoJitInfoTableChunk **new1p, MonoJitInfoTableChunk **new2p)
549 MonoJitInfoTableChunk *new1 = jit_info_table_new_chunk ();
550 MonoJitInfoTableChunk *new2 = jit_info_table_new_chunk ();
552 g_assert (chunk->num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE);
554 new1->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE / 2;
555 new2->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE - new1->num_elements;
557 memcpy ((void*)new1->data, (void*)chunk->data, sizeof (MonoJitInfo*) * new1->num_elements);
558 memcpy ((void*)new2->data, (void*)(chunk->data + new1->num_elements), sizeof (MonoJitInfo*) * new2->num_elements);
560 new1->last_code_end = (gint8*)new1->data [new1->num_elements - 1]->code_start
561 + new1->data [new1->num_elements - 1]->code_size;
562 new2->last_code_end = (gint8*)new2->data [new2->num_elements - 1]->code_start
563 + new2->data [new2->num_elements - 1]->code_size;
569 static MonoJitInfoTable*
570 jit_info_table_copy_and_split_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
572 MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
573 + sizeof (MonoJitInfoTableChunk*) * (table->num_chunks + 1));
576 new_table->domain = table->domain;
577 new_table->num_chunks = table->num_chunks + 1;
580 for (i = 0; i < table->num_chunks; ++i) {
581 if (table->chunks [i] == chunk) {
582 jit_info_table_split_chunk (chunk, &new_table->chunks [j], &new_table->chunks [j + 1]);
585 new_table->chunks [j] = table->chunks [i];
586 ++new_table->chunks [j]->refcount;
591 g_assert (j == new_table->num_chunks);
596 static MonoJitInfoTableChunk*
597 jit_info_table_purify_chunk (MonoJitInfoTableChunk *old)
599 MonoJitInfoTableChunk *new = jit_info_table_new_chunk ();
603 for (i = 0; i < old->num_elements; ++i) {
604 if (!IS_JIT_INFO_TOMBSTONE (old->data [i]))
605 new->data [j++] = old->data [i];
608 new->num_elements = j;
609 if (new->num_elements > 0)
610 new->last_code_end = (gint8*)new->data [j - 1]->code_start + new->data [j - 1]->code_size;
612 new->last_code_end = old->last_code_end;
617 static MonoJitInfoTable*
618 jit_info_table_copy_and_purify_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
620 MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
621 + sizeof (MonoJitInfoTableChunk*) * table->num_chunks);
624 new_table->domain = table->domain;
625 new_table->num_chunks = table->num_chunks;
628 for (i = 0; i < table->num_chunks; ++i) {
629 if (table->chunks [i] == chunk)
630 new_table->chunks [j++] = jit_info_table_purify_chunk (table->chunks [i]);
632 new_table->chunks [j] = table->chunks [i];
633 ++new_table->chunks [j]->refcount;
638 g_assert (j == new_table->num_chunks);
643 /* As we add an element to the table the case can arise that the chunk
644 * to which we need to add is already full. In that case we have to
645 * allocate a new table and do something about that chunk. We have
646 * several strategies:
648 * If the number of elements in the table is below the low watermark
649 * or above the high watermark, we reallocate the whole table.
650 * Otherwise we only concern ourselves with the overflowing chunk:
652 * If there are no tombstones in the chunk then we split the chunk in
653 * two, each half full.
655 * If the chunk does contain tombstones, we just make a new copy of
656 * the chunk without the tombstones, which will have room for at least
657 * the one element we have to add.
659 static MonoJitInfoTable*
660 jit_info_table_chunk_overflow (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
662 int num_elements = jit_info_table_num_elements (table);
665 if (num_elements < JIT_INFO_TABLE_LOW_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)
666 || num_elements > JIT_INFO_TABLE_HIGH_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)) {
667 //printf ("reallocing table\n");
668 return jit_info_table_realloc (table);
671 /* count the number of non-tombstone elements in the chunk */
673 for (i = 0; i < chunk->num_elements; ++i) {
674 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [i]))
678 if (num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
679 //printf ("splitting chunk\n");
680 return jit_info_table_copy_and_split_chunk (table, chunk);
683 //printf ("purifying chunk\n");
684 return jit_info_table_copy_and_purify_chunk (table, chunk);
687 /* We add elements to the table by first making space for them by
688 * shifting the elements at the back to the right, one at a time.
689 * This results in duplicate entries during the process, but during
690 * all the time the table is in a sorted state. Also, when an element
691 * is replaced by another one, the element that replaces it has an end
692 * address that is equal to or lower than that of the replaced
693 * element. That property is necessary to guarantee that when
694 * searching for an element we end up at a position not higher than
695 * the one we're looking for (i.e. we either find the element directly
696 * or we end up to the left of it).
699 jit_info_table_add (MonoDomain *domain, MonoJitInfoTable *volatile *table_ptr, MonoJitInfo *ji)
701 MonoJitInfoTable *table;
702 MonoJitInfoTableChunk *chunk;
710 chunk_pos = jit_info_table_index (table, (gint8*)ji->code_start + ji->code_size);
711 g_assert (chunk_pos < table->num_chunks);
712 chunk = table->chunks [chunk_pos];
714 if (chunk->num_elements >= MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
715 MonoJitInfoTable *new_table = jit_info_table_chunk_overflow (table, chunk);
717 /* Debugging code, should be removed. */
718 //jit_info_table_check (new_table);
720 *table_ptr = new_table;
721 mono_memory_barrier ();
722 domain->num_jit_info_tables++;
723 mono_thread_hazardous_free_or_queue (table, (MonoHazardousFreeFunc)jit_info_table_free, TRUE, FALSE);
729 /* Debugging code, should be removed. */
730 //jit_info_table_check (table);
732 num_elements = chunk->num_elements;
734 pos = jit_info_table_chunk_index (chunk, NULL, (gint8*)ji->code_start + ji->code_size);
736 /* First we need to size up the chunk by one, by copying the
737 last item, or inserting the first one, if the table is
739 if (num_elements > 0)
740 chunk->data [num_elements] = chunk->data [num_elements - 1];
742 chunk->data [0] = ji;
743 mono_memory_write_barrier ();
744 chunk->num_elements = ++num_elements;
746 /* Shift the elements up one by one. */
747 for (i = num_elements - 2; i >= pos; --i) {
748 mono_memory_write_barrier ();
749 chunk->data [i + 1] = chunk->data [i];
752 /* Now we have room and can insert the new item. */
753 mono_memory_write_barrier ();
754 chunk->data [pos] = ji;
756 /* Set the high code end address chunk entry. */
757 chunk->last_code_end = (gint8*)chunk->data [chunk->num_elements - 1]->code_start
758 + chunk->data [chunk->num_elements - 1]->code_size;
760 /* Debugging code, should be removed. */
761 //jit_info_table_check (table);
765 mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
767 g_assert (ji->d.method != NULL);
769 mono_domain_lock (domain);
771 ++mono_stats.jit_info_table_insert_count;
773 jit_info_table_add (domain, &domain->jit_info_table, ji);
775 mono_domain_unlock (domain);
779 mono_jit_info_make_tombstone (MonoJitInfo *ji)
781 MonoJitInfo *tombstone = g_new0 (MonoJitInfo, 1);
783 tombstone->code_start = ji->code_start;
784 tombstone->code_size = ji->code_size;
785 tombstone->d.method = JIT_INFO_TOMBSTONE_MARKER;
791 * LOCKING: domain lock
794 mono_jit_info_free_or_queue (MonoDomain *domain, MonoJitInfo *ji)
796 if (domain->num_jit_info_tables <= 1) {
797 /* Can it actually happen that we only have one table
798 but ji is still hazardous? */
799 mono_thread_hazardous_free_or_queue (ji, g_free, TRUE, FALSE);
801 domain->jit_info_free_queue = g_slist_prepend (domain->jit_info_free_queue, ji);
806 jit_info_table_remove (MonoJitInfoTable *table, MonoJitInfo *ji)
808 MonoJitInfoTableChunk *chunk;
809 gpointer start = ji->code_start;
812 chunk_pos = jit_info_table_index (table, start);
813 g_assert (chunk_pos < table->num_chunks);
815 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], NULL, start);
818 chunk = table->chunks [chunk_pos];
820 while (pos < chunk->num_elements) {
821 if (chunk->data [pos] == ji)
824 g_assert (IS_JIT_INFO_TOMBSTONE (chunk->data [pos]));
825 g_assert ((guint8*)chunk->data [pos]->code_start + chunk->data [pos]->code_size
826 <= (guint8*)ji->code_start + ji->code_size);
833 } while (chunk_pos < table->num_chunks);
836 g_assert (chunk->data [pos] == ji);
838 chunk->data [pos] = mono_jit_info_make_tombstone (ji);
840 /* Debugging code, should be removed. */
841 //jit_info_table_check (table);
845 mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
847 MonoJitInfoTable *table;
849 mono_domain_lock (domain);
850 table = domain->jit_info_table;
852 ++mono_stats.jit_info_table_remove_count;
854 jit_info_table_remove (table, ji);
856 mono_jit_info_free_or_queue (domain, ji);
858 mono_domain_unlock (domain);
862 mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
866 g_assert (mono_root_domain);
867 mono_domain_lock (mono_root_domain);
870 * We reuse MonoJitInfoTable to store AOT module info,
871 * this gives us async-safe lookup.
873 if (!mono_root_domain->aot_modules) {
874 mono_root_domain->num_jit_info_tables ++;
875 mono_root_domain->aot_modules = jit_info_table_new (mono_root_domain);
878 ji = g_new0 (MonoJitInfo, 1);
880 ji->code_start = start;
881 ji->code_size = (guint8*)end - (guint8*)start;
882 jit_info_table_add (mono_root_domain, &mono_root_domain->aot_modules, ji);
884 mono_domain_unlock (mono_root_domain);
888 mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func)
890 jit_info_find_in_aot_func = func;
894 mono_jit_info_get_code_start (MonoJitInfo* ji)
896 return ji->code_start;
900 mono_jit_info_get_code_size (MonoJitInfo* ji)
902 return ji->code_size;
906 mono_jit_info_get_method (MonoJitInfo* ji)
908 g_assert (!ji->async);
913 jit_info_key_extract (gpointer value)
915 MonoJitInfo *info = (MonoJitInfo*)value;
917 return info->d.method;
921 jit_info_next_value (gpointer value)
923 MonoJitInfo *info = (MonoJitInfo*)value;
925 return (gpointer*)&info->next_jit_code_hash;
929 mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
931 mono_internal_hash_table_init (jit_code_hash,
932 mono_aligned_addr_hash,
933 jit_info_key_extract,
934 jit_info_next_value);
938 mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
940 if (ji->has_generic_jit_info)
941 return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
947 * mono_jit_info_get_generic_sharing_context:
950 * Returns the jit info's generic sharing context, or NULL if it
953 MonoGenericSharingContext*
954 mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
956 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
959 return gi->generic_sharing_context;
965 * mono_jit_info_set_generic_sharing_context:
967 * @gsctx: a generic sharing context
969 * Sets the jit info's generic sharing context. The jit info must
970 * have memory allocated for the context.
973 mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
975 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
979 gi->generic_sharing_context = gsctx;
982 MonoTryBlockHoleTableJitInfo*
983 mono_jit_info_get_try_block_hole_table_info (MonoJitInfo *ji)
985 if (ji->has_try_block_holes) {
986 char *ptr = (char*)&ji->clauses [ji->num_clauses];
987 if (ji->has_generic_jit_info)
988 ptr += sizeof (MonoGenericJitInfo);
989 return (MonoTryBlockHoleTableJitInfo*)ptr;
996 try_block_hole_table_size (MonoJitInfo *ji)
998 MonoTryBlockHoleTableJitInfo *table;
1000 table = mono_jit_info_get_try_block_hole_table_info (ji);
1002 return sizeof (MonoTryBlockHoleTableJitInfo) + table->num_holes * sizeof (MonoTryBlockHoleJitInfo);
1006 mono_jit_info_get_arch_eh_info (MonoJitInfo *ji)
1008 if (ji->has_arch_eh_info) {
1009 char *ptr = (char*)&ji->clauses [ji->num_clauses];
1010 if (ji->has_generic_jit_info)
1011 ptr += sizeof (MonoGenericJitInfo);
1012 if (ji->has_try_block_holes)
1013 ptr += try_block_hole_table_size (ji);
1014 return (MonoArchEHJitInfo*)ptr;
1021 mono_jit_info_get_cas_info (MonoJitInfo *ji)
1023 if (ji->has_cas_info) {
1024 char *ptr = (char*)&ji->clauses [ji->num_clauses];
1025 if (ji->has_generic_jit_info)
1026 ptr += sizeof (MonoGenericJitInfo);
1027 if (ji->has_try_block_holes)
1028 ptr += try_block_hole_table_size (ji);
1029 if (ji->has_arch_eh_info)
1030 ptr += sizeof (MonoArchEHJitInfo);
1031 return (MonoMethodCasInfo*)ptr;
1037 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
1038 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
1040 static LockFreeMempool*
1041 lock_free_mempool_new (void)
1043 return g_new0 (LockFreeMempool, 1);
1047 lock_free_mempool_free (LockFreeMempool *mp)
1049 LockFreeMempoolChunk *chunk, *next;
1054 mono_vfree (chunk, mono_pagesize ());
1061 * This is async safe
1063 static LockFreeMempoolChunk*
1064 lock_free_mempool_chunk_new (LockFreeMempool *mp, int len)
1066 LockFreeMempoolChunk *chunk, *prev;
1069 size = mono_pagesize ();
1070 while (size - sizeof (LockFreeMempoolChunk) < len)
1071 size += mono_pagesize ();
1072 chunk = mono_valloc (0, size, MONO_MMAP_READ|MONO_MMAP_WRITE);
1074 chunk->mem = ALIGN_PTR_TO ((char*)chunk + sizeof (LockFreeMempoolChunk), 16);
1075 chunk->size = ((char*)chunk + size) - (char*)chunk->mem;
1078 /* Add to list of chunks lock-free */
1081 if (InterlockedCompareExchangePointer ((volatile gpointer*)&mp->chunks, chunk, prev) == prev)
1090 * This is async safe
1093 lock_free_mempool_alloc0 (LockFreeMempool *mp, guint size)
1095 LockFreeMempoolChunk *chunk;
1099 // FIXME: Free the allocator
1101 size = ALIGN_TO (size, 8);
1102 chunk = mp->current;
1104 chunk = lock_free_mempool_chunk_new (mp, size);
1105 mono_memory_barrier ();
1107 mp->current = chunk;
1110 /* The code below is lock-free, 'chunk' is shared state */
1111 oldpos = InterlockedExchangeAdd (&chunk->pos, size);
1112 if (oldpos + size > chunk->size) {
1113 chunk = lock_free_mempool_chunk_new (mp, size);
1114 g_assert (chunk->pos + size <= chunk->size);
1117 mono_memory_barrier ();
1118 mp->current = chunk;
1120 res = (char*)chunk->mem + oldpos;
1127 mono_install_create_domain_hook (MonoCreateDomainFunc func)
1129 create_domain_hook = func;
1133 mono_install_free_domain_hook (MonoFreeDomainFunc func)
1135 free_domain_hook = func;
1139 * mono_string_equal:
1140 * @s1: First string to compare
1141 * @s2: Second string to compare
1143 * Returns FALSE if the strings differ.
1146 mono_string_equal (MonoString *s1, MonoString *s2)
1148 int l1 = mono_string_length (s1);
1149 int l2 = mono_string_length (s2);
1156 return memcmp (mono_string_chars (s1), mono_string_chars (s2), l1 * 2) == 0;
1161 * @s: the string to hash
1163 * Returns the hash for the string.
1166 mono_string_hash (MonoString *s)
1168 const guint16 *p = mono_string_chars (s);
1169 int i, len = mono_string_length (s);
1172 for (i = 0; i < len; i++) {
1173 h = (h << 5) - h + *p;
1181 mono_ptrarray_equal (gpointer *s1, gpointer *s2)
1183 int len = GPOINTER_TO_INT (s1 [0]);
1184 if (len != GPOINTER_TO_INT (s2 [0]))
1187 return memcmp (s1 + 1, s2 + 1, len * sizeof(gpointer)) == 0;
1191 mono_ptrarray_hash (gpointer *s)
1194 int len = GPOINTER_TO_INT (s [0]);
1197 for (i = 1; i < len; i++)
1198 hash += GPOINTER_TO_UINT (s [i]);
1204 * Allocate an id for domain and set domain->domain_id.
1205 * LOCKING: must be called while holding appdomains_mutex.
1206 * We try to assign low numbers to the domain, so it can be used
1207 * as an index in data tables to lookup domain-specific info
1208 * with minimal memory overhead. We also try not to reuse the
1209 * same id too quickly (to help debugging).
1212 domain_id_alloc (MonoDomain *domain)
1215 if (!appdomains_list) {
1216 appdomain_list_size = 2;
1217 appdomains_list = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1219 for (i = appdomain_next; i < appdomain_list_size; ++i) {
1220 if (!appdomains_list [i]) {
1226 for (i = 0; i < appdomain_next; ++i) {
1227 if (!appdomains_list [i]) {
1234 MonoDomain **new_list;
1235 int new_size = appdomain_list_size * 2;
1236 if (new_size >= (1 << 16))
1237 g_assert_not_reached ();
1238 id = appdomain_list_size;
1239 new_list = mono_gc_alloc_fixed (new_size * sizeof (void*), NULL);
1240 memcpy (new_list, appdomains_list, appdomain_list_size * sizeof (void*));
1241 mono_gc_free_fixed (appdomains_list);
1242 appdomains_list = new_list;
1243 appdomain_list_size = new_size;
1245 domain->domain_id = id;
1246 appdomains_list [id] = domain;
1248 if (appdomain_next > appdomain_list_size)
1253 static gsize domain_gc_bitmap [sizeof(MonoDomain)/4/32 + 1];
1254 static gpointer domain_gc_desc = NULL;
1255 static guint32 domain_shadow_serial = 0L;
1258 mono_domain_create (void)
1261 guint32 shadow_serial;
1263 mono_appdomains_lock ();
1264 shadow_serial = domain_shadow_serial++;
1266 if (!domain_gc_desc) {
1267 unsigned int i, bit = 0;
1268 for (i = G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_OBJECT); i < G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_GC_TRACKED); i += sizeof (gpointer)) {
1269 bit = i / sizeof (gpointer);
1270 domain_gc_bitmap [bit / 32] |= (gsize) 1 << (bit % 32);
1272 domain_gc_desc = mono_gc_make_descr_from_bitmap ((gsize*)domain_gc_bitmap, bit + 1);
1274 mono_appdomains_unlock ();
1276 #ifdef HAVE_BOEHM_GC
1278 * Boehm doesn't like roots inside GC allocated objects, and alloc_fixed returns
1279 * a GC_MALLOC-ed object, contrary to the api docs. This causes random crashes when
1280 * running the corlib test suite.
1281 * To solve this, we pass a NULL descriptor, and don't register roots.
1283 domain = mono_gc_alloc_fixed (sizeof (MonoDomain), NULL);
1285 domain = mono_gc_alloc_fixed (sizeof (MonoDomain), domain_gc_desc);
1286 mono_gc_register_root ((char*)&(domain->MONO_DOMAIN_FIRST_GC_TRACKED), G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_LAST_GC_TRACKED) - G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_GC_TRACKED), NULL);
1288 domain->shadow_serial = shadow_serial;
1289 domain->domain = NULL;
1290 domain->setup = NULL;
1291 domain->friendly_name = NULL;
1292 domain->search_path = NULL;
1294 mono_profiler_appdomain_event (domain, MONO_PROFILE_START_LOAD);
1296 domain->mp = mono_mempool_new ();
1297 domain->code_mp = mono_code_manager_new ();
1298 domain->lock_free_mp = lock_free_mempool_new ();
1299 domain->env = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1300 domain->domain_assemblies = NULL;
1301 domain->assembly_bindings = NULL;
1302 domain->assembly_bindings_parsed = FALSE;
1303 domain->class_vtable_array = g_ptr_array_new ();
1304 domain->proxy_vtable_hash = g_hash_table_new ((GHashFunc)mono_ptrarray_hash, (GCompareFunc)mono_ptrarray_equal);
1305 domain->static_data_array = NULL;
1306 mono_jit_code_hash_init (&domain->jit_code_hash);
1307 domain->ldstr_table = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1308 domain->num_jit_info_tables = 1;
1309 domain->jit_info_table = jit_info_table_new (domain);
1310 domain->jit_info_free_queue = NULL;
1311 domain->finalizable_objects_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1312 domain->ftnptrs_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1314 mono_mutex_init_recursive (&domain->lock);
1315 mono_mutex_init_recursive (&domain->assemblies_lock);
1316 mono_mutex_init_recursive (&domain->jit_code_hash_lock);
1317 mono_mutex_init_recursive (&domain->finalizable_objects_hash_lock);
1319 domain->method_rgctx_hash = NULL;
1321 mono_appdomains_lock ();
1322 domain_id_alloc (domain);
1323 mono_appdomains_unlock ();
1325 #ifndef DISABLE_PERFCOUNTERS
1326 mono_perfcounters->loader_appdomains++;
1327 mono_perfcounters->loader_total_appdomains++;
1330 mono_debug_domain_create (domain);
1332 if (create_domain_hook)
1333 create_domain_hook (domain);
1335 mono_profiler_appdomain_loaded (domain, MONO_PROFILE_OK);
1341 * mono_init_internal:
1343 * Creates the initial application domain and initializes the mono_defaults
1345 * This function is guaranteed to not run any IL code.
1346 * If exe_filename is not NULL, the method will determine the required runtime
1347 * from the exe configuration file or the version PE field.
1348 * If runtime_version is not NULL, that runtime version will be used.
1349 * Either exe_filename or runtime_version must be provided.
1351 * Returns: the initial domain.
1354 mono_init_internal (const char *filename, const char *exe_filename, const char *runtime_version)
1356 static MonoDomain *domain = NULL;
1357 MonoAssembly *ass = NULL;
1358 MonoImageOpenStatus status = MONO_IMAGE_OK;
1359 const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
1362 #ifdef DEBUG_DOMAIN_UNLOAD
1363 debug_domain_unload = TRUE;
1367 g_assert_not_reached ();
1370 /* Avoid system error message boxes. */
1371 SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1378 #ifndef DISABLE_PERFCOUNTERS
1379 mono_perfcounters_init ();
1382 mono_counters_register ("Max native code in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_size);
1383 mono_counters_register ("Max code space allocated in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_alloc);
1384 mono_counters_register ("Total code space allocated", MONO_COUNTER_INT|MONO_COUNTER_JIT, &total_domain_code_alloc);
1386 mono_gc_base_init ();
1388 MONO_FAST_TLS_INIT (tls_appdomain);
1389 mono_native_tls_alloc (&appdomain_thread_id, NULL);
1391 mono_mutex_init_recursive (&appdomains_mutex);
1393 mono_metadata_init ();
1394 mono_images_init ();
1395 mono_assemblies_init ();
1396 mono_classes_init ();
1397 mono_loader_init ();
1398 mono_reflection_init ();
1399 mono_runtime_init_tls ();
1401 /* FIXME: When should we release this memory? */
1402 MONO_GC_REGISTER_ROOT_FIXED (appdomains_list);
1404 domain = mono_domain_create ();
1405 mono_root_domain = domain;
1407 SET_APPDOMAIN (domain);
1409 /* Get a list of runtimes supported by the exe */
1410 if (exe_filename != NULL) {
1412 * This function will load the exe file as a MonoImage. We need to close it, but
1413 * that would mean it would be reloaded later. So instead, we save it to
1414 * exe_image, and close it during shutdown.
1416 get_runtimes_from_exe (exe_filename, &exe_image, runtimes);
1419 exe_image = mono_assembly_open_from_bundle (exe_filename, NULL, FALSE);
1421 exe_image = mono_image_open (exe_filename, NULL);
1423 mono_fixup_exe_image (exe_image);
1425 } else if (runtime_version != NULL) {
1426 runtimes [0] = get_runtime_by_version (runtime_version);
1427 runtimes [1] = NULL;
1430 if (runtimes [0] == NULL) {
1431 const MonoRuntimeInfo *default_runtime = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
1432 runtimes [0] = default_runtime;
1433 runtimes [1] = NULL;
1434 g_print ("WARNING: The runtime version supported by this application is unavailable.\n");
1435 g_print ("Using default runtime: %s\n", default_runtime->runtime_version);
1438 /* The selected runtime will be the first one for which there is a mscrolib.dll */
1439 for (n = 0; runtimes [n] != NULL && ass == NULL; n++) {
1440 current_runtime = runtimes [n];
1441 ass = mono_assembly_load_corlib (current_runtime, &status);
1442 if (status != MONO_IMAGE_OK && status != MONO_IMAGE_ERROR_ERRNO)
1447 if ((status != MONO_IMAGE_OK) || (ass == NULL)) {
1449 case MONO_IMAGE_ERROR_ERRNO: {
1450 char *corlib_file = g_build_filename (mono_assembly_getrootdir (), "mono", current_runtime->framework_version, "mscorlib.dll", NULL);
1451 g_print ("The assembly mscorlib.dll was not found or could not be loaded.\n");
1452 g_print ("It should have been installed in the `%s' directory.\n", corlib_file);
1453 g_free (corlib_file);
1456 case MONO_IMAGE_IMAGE_INVALID:
1457 g_print ("The file %s/mscorlib.dll is an invalid CIL image\n",
1458 mono_assembly_getrootdir ());
1460 case MONO_IMAGE_MISSING_ASSEMBLYREF:
1461 g_print ("Missing assembly reference in %s/mscorlib.dll\n",
1462 mono_assembly_getrootdir ());
1465 /* to suppress compiler warning */
1471 mono_defaults.corlib = mono_assembly_get_image (ass);
1473 mono_defaults.object_class = mono_class_from_name (
1474 mono_defaults.corlib, "System", "Object");
1475 g_assert (mono_defaults.object_class != 0);
1477 mono_defaults.void_class = mono_class_from_name (
1478 mono_defaults.corlib, "System", "Void");
1479 g_assert (mono_defaults.void_class != 0);
1481 mono_defaults.boolean_class = mono_class_from_name (
1482 mono_defaults.corlib, "System", "Boolean");
1483 g_assert (mono_defaults.boolean_class != 0);
1485 mono_defaults.byte_class = mono_class_from_name (
1486 mono_defaults.corlib, "System", "Byte");
1487 g_assert (mono_defaults.byte_class != 0);
1489 mono_defaults.sbyte_class = mono_class_from_name (
1490 mono_defaults.corlib, "System", "SByte");
1491 g_assert (mono_defaults.sbyte_class != 0);
1493 mono_defaults.int16_class = mono_class_from_name (
1494 mono_defaults.corlib, "System", "Int16");
1495 g_assert (mono_defaults.int16_class != 0);
1497 mono_defaults.uint16_class = mono_class_from_name (
1498 mono_defaults.corlib, "System", "UInt16");
1499 g_assert (mono_defaults.uint16_class != 0);
1501 mono_defaults.int32_class = mono_class_from_name (
1502 mono_defaults.corlib, "System", "Int32");
1503 g_assert (mono_defaults.int32_class != 0);
1505 mono_defaults.uint32_class = mono_class_from_name (
1506 mono_defaults.corlib, "System", "UInt32");
1507 g_assert (mono_defaults.uint32_class != 0);
1509 mono_defaults.uint_class = mono_class_from_name (
1510 mono_defaults.corlib, "System", "UIntPtr");
1511 g_assert (mono_defaults.uint_class != 0);
1513 mono_defaults.int_class = mono_class_from_name (
1514 mono_defaults.corlib, "System", "IntPtr");
1515 g_assert (mono_defaults.int_class != 0);
1517 mono_defaults.int64_class = mono_class_from_name (
1518 mono_defaults.corlib, "System", "Int64");
1519 g_assert (mono_defaults.int64_class != 0);
1521 mono_defaults.uint64_class = mono_class_from_name (
1522 mono_defaults.corlib, "System", "UInt64");
1523 g_assert (mono_defaults.uint64_class != 0);
1525 mono_defaults.single_class = mono_class_from_name (
1526 mono_defaults.corlib, "System", "Single");
1527 g_assert (mono_defaults.single_class != 0);
1529 mono_defaults.double_class = mono_class_from_name (
1530 mono_defaults.corlib, "System", "Double");
1531 g_assert (mono_defaults.double_class != 0);
1533 mono_defaults.char_class = mono_class_from_name (
1534 mono_defaults.corlib, "System", "Char");
1535 g_assert (mono_defaults.char_class != 0);
1537 mono_defaults.string_class = mono_class_from_name (
1538 mono_defaults.corlib, "System", "String");
1539 g_assert (mono_defaults.string_class != 0);
1541 mono_defaults.enum_class = mono_class_from_name (
1542 mono_defaults.corlib, "System", "Enum");
1543 g_assert (mono_defaults.enum_class != 0);
1545 mono_defaults.array_class = mono_class_from_name (
1546 mono_defaults.corlib, "System", "Array");
1547 g_assert (mono_defaults.array_class != 0);
1549 mono_defaults.delegate_class = mono_class_from_name (
1550 mono_defaults.corlib, "System", "Delegate");
1551 g_assert (mono_defaults.delegate_class != 0 );
1553 mono_defaults.multicastdelegate_class = mono_class_from_name (
1554 mono_defaults.corlib, "System", "MulticastDelegate");
1555 g_assert (mono_defaults.multicastdelegate_class != 0 );
1557 mono_defaults.asyncresult_class = mono_class_from_name (
1558 mono_defaults.corlib, "System.Runtime.Remoting.Messaging",
1560 g_assert (mono_defaults.asyncresult_class != 0 );
1562 mono_defaults.manualresetevent_class = mono_class_from_name (
1563 mono_defaults.corlib, "System.Threading", "ManualResetEvent");
1564 g_assert (mono_defaults.manualresetevent_class != 0 );
1566 mono_defaults.typehandle_class = mono_class_from_name (
1567 mono_defaults.corlib, "System", "RuntimeTypeHandle");
1568 g_assert (mono_defaults.typehandle_class != 0);
1570 mono_defaults.methodhandle_class = mono_class_from_name (
1571 mono_defaults.corlib, "System", "RuntimeMethodHandle");
1572 g_assert (mono_defaults.methodhandle_class != 0);
1574 mono_defaults.fieldhandle_class = mono_class_from_name (
1575 mono_defaults.corlib, "System", "RuntimeFieldHandle");
1576 g_assert (mono_defaults.fieldhandle_class != 0);
1578 mono_defaults.systemtype_class = mono_class_from_name (
1579 mono_defaults.corlib, "System", "Type");
1580 g_assert (mono_defaults.systemtype_class != 0);
1582 mono_defaults.monotype_class = mono_class_from_name (
1583 mono_defaults.corlib, "System", "MonoType");
1584 g_assert (mono_defaults.monotype_class != 0);
1586 mono_defaults.exception_class = mono_class_from_name (
1587 mono_defaults.corlib, "System", "Exception");
1588 g_assert (mono_defaults.exception_class != 0);
1590 mono_defaults.threadabortexception_class = mono_class_from_name (
1591 mono_defaults.corlib, "System.Threading", "ThreadAbortException");
1592 g_assert (mono_defaults.threadabortexception_class != 0);
1594 mono_defaults.thread_class = mono_class_from_name (
1595 mono_defaults.corlib, "System.Threading", "Thread");
1596 g_assert (mono_defaults.thread_class != 0);
1598 mono_defaults.internal_thread_class = mono_class_from_name (
1599 mono_defaults.corlib, "System.Threading", "InternalThread");
1600 if (!mono_defaults.internal_thread_class) {
1601 /* This can happen with an old mscorlib */
1602 fprintf (stderr, "Corlib too old for this runtime.\n");
1603 fprintf (stderr, "Loaded from: %s\n",
1604 mono_defaults.corlib? mono_image_get_filename (mono_defaults.corlib): "unknown");
1608 mono_defaults.appdomain_class = mono_class_from_name (
1609 mono_defaults.corlib, "System", "AppDomain");
1610 g_assert (mono_defaults.appdomain_class != 0);
1612 #ifndef DISABLE_REMOTING
1613 mono_defaults.transparent_proxy_class = mono_class_from_name (
1614 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "TransparentProxy");
1615 g_assert (mono_defaults.transparent_proxy_class != 0);
1617 mono_defaults.real_proxy_class = mono_class_from_name (
1618 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "RealProxy");
1619 g_assert (mono_defaults.real_proxy_class != 0);
1621 mono_defaults.marshalbyrefobject_class = mono_class_from_name (
1622 mono_defaults.corlib, "System", "MarshalByRefObject");
1623 g_assert (mono_defaults.marshalbyrefobject_class != 0);
1625 mono_defaults.iremotingtypeinfo_class = mono_class_from_name (
1626 mono_defaults.corlib, "System.Runtime.Remoting", "IRemotingTypeInfo");
1627 g_assert (mono_defaults.iremotingtypeinfo_class != 0);
1630 mono_defaults.mono_method_message_class = mono_class_from_name (
1631 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", "MonoMethodMessage");
1632 g_assert (mono_defaults.mono_method_message_class != 0);
1634 mono_defaults.field_info_class = mono_class_from_name (
1635 mono_defaults.corlib, "System.Reflection", "FieldInfo");
1636 g_assert (mono_defaults.field_info_class != 0);
1638 mono_defaults.method_info_class = mono_class_from_name (
1639 mono_defaults.corlib, "System.Reflection", "MethodInfo");
1640 g_assert (mono_defaults.method_info_class != 0);
1642 mono_defaults.stringbuilder_class = mono_class_from_name (
1643 mono_defaults.corlib, "System.Text", "StringBuilder");
1644 g_assert (mono_defaults.stringbuilder_class != 0);
1646 mono_defaults.math_class = mono_class_from_name (
1647 mono_defaults.corlib, "System", "Math");
1648 g_assert (mono_defaults.math_class != 0);
1650 mono_defaults.stack_frame_class = mono_class_from_name (
1651 mono_defaults.corlib, "System.Diagnostics", "StackFrame");
1652 g_assert (mono_defaults.stack_frame_class != 0);
1654 mono_defaults.stack_trace_class = mono_class_from_name (
1655 mono_defaults.corlib, "System.Diagnostics", "StackTrace");
1656 g_assert (mono_defaults.stack_trace_class != 0);
1658 mono_defaults.marshal_class = mono_class_from_name (
1659 mono_defaults.corlib, "System.Runtime.InteropServices", "Marshal");
1660 g_assert (mono_defaults.marshal_class != 0);
1662 mono_defaults.typed_reference_class = mono_class_from_name (
1663 mono_defaults.corlib, "System", "TypedReference");
1664 g_assert (mono_defaults.typed_reference_class != 0);
1666 mono_defaults.argumenthandle_class = mono_class_from_name (
1667 mono_defaults.corlib, "System", "RuntimeArgumentHandle");
1668 g_assert (mono_defaults.argumenthandle_class != 0);
1670 mono_defaults.monitor_class = mono_class_from_name (
1671 mono_defaults.corlib, "System.Threading", "Monitor");
1672 g_assert (mono_defaults.monitor_class != 0);
1674 mono_defaults.runtimesecurityframe_class = mono_class_from_name (
1675 mono_defaults.corlib, "System.Security", "RuntimeSecurityFrame");
1677 mono_defaults.executioncontext_class = mono_class_from_name (
1678 mono_defaults.corlib, "System.Threading", "ExecutionContext");
1680 mono_defaults.internals_visible_class = mono_class_from_name (
1681 mono_defaults.corlib, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute");
1683 mono_defaults.critical_finalizer_object = mono_class_from_name (
1684 mono_defaults.corlib, "System.Runtime.ConstrainedExecution", "CriticalFinalizerObject");
1687 * mscorlib needs a little help, only now it can load its friends list (after we have
1688 * loaded the InternalsVisibleToAttribute), load it now
1690 mono_assembly_load_friends (ass);
1692 mono_defaults.safehandle_class = mono_class_from_name (
1693 mono_defaults.corlib, "System.Runtime.InteropServices", "SafeHandle");
1695 mono_defaults.handleref_class = mono_class_from_name (
1696 mono_defaults.corlib, "System.Runtime.InteropServices", "HandleRef");
1698 mono_defaults.attribute_class = mono_class_from_name (
1699 mono_defaults.corlib, "System", "Attribute");
1701 mono_defaults.customattribute_data_class = mono_class_from_name (
1702 mono_defaults.corlib, "System.Reflection", "CustomAttributeData");
1704 /* these are initialized lazily when COM features are used */
1706 mono_class_init (mono_defaults.array_class);
1707 mono_defaults.generic_nullable_class = mono_class_from_name (
1708 mono_defaults.corlib, "System", "Nullable`1");
1709 mono_defaults.generic_ilist_class = mono_class_from_name (
1710 mono_defaults.corlib, "System.Collections.Generic", "IList`1");
1711 mono_defaults.generic_ireadonlylist_class = mono_class_from_name (
1712 mono_defaults.corlib, "System.Collections.Generic", "IReadOnlyList`1");
1714 domain->friendly_name = g_path_get_basename (filename);
1716 _mono_debug_init_corlib (domain);
1724 * Creates the initial application domain and initializes the mono_defaults
1726 * This function is guaranteed to not run any IL code.
1727 * The runtime is initialized using the default runtime version.
1729 * Returns: the initial domain.
1732 mono_init (const char *domain_name)
1734 return mono_init_internal (domain_name, NULL, DEFAULT_RUNTIME_VERSION);
1738 * mono_init_from_assembly:
1739 * @domain_name: name to give to the initial domain
1740 * @filename: filename to load on startup
1742 * Used by the runtime, users should use mono_jit_init instead.
1744 * Creates the initial application domain and initializes the mono_defaults
1746 * This function is guaranteed to not run any IL code.
1747 * The runtime is initialized using the runtime version required by the
1748 * provided executable. The version is determined by looking at the exe
1749 * configuration file and the version PE field)
1751 * Returns: the initial domain.
1754 mono_init_from_assembly (const char *domain_name, const char *filename)
1756 return mono_init_internal (domain_name, filename, NULL);
1760 * mono_init_version:
1762 * Used by the runtime, users should use mono_jit_init instead.
1764 * Creates the initial application domain and initializes the mono_defaults
1767 * This function is guaranteed to not run any IL code.
1768 * The runtime is initialized using the provided rutime version.
1770 * Returns: the initial domain.
1773 mono_init_version (const char *domain_name, const char *version)
1775 return mono_init_internal (domain_name, NULL, version);
1781 * Cleans up all metadata modules.
1786 mono_close_exe_image ();
1788 mono_defaults.corlib = NULL;
1790 mono_config_cleanup ();
1791 mono_loader_cleanup ();
1792 mono_classes_cleanup ();
1793 mono_assemblies_cleanup ();
1794 mono_images_cleanup ();
1795 mono_debug_cleanup ();
1796 mono_metadata_cleanup ();
1798 mono_native_tls_free (appdomain_thread_id);
1799 mono_mutex_destroy (&appdomains_mutex);
1807 mono_close_exe_image (void)
1810 mono_image_close (exe_image);
1814 * mono_get_root_domain:
1816 * The root AppDomain is the initial domain created by the runtime when it is
1817 * initialized. Programs execute on this AppDomain, but can create new ones
1818 * later. Currently there is no unmanaged API to create new AppDomains, this
1819 * must be done from managed code.
1821 * Returns: the root appdomain, to obtain the current domain, use mono_domain_get ()
1824 mono_get_root_domain (void)
1826 return mono_root_domain;
1832 * Returns: the current domain, to obtain the root domain use
1833 * mono_get_root_domain().
1838 return GET_APPDOMAIN ();
1842 mono_domain_unset (void)
1844 SET_APPDOMAIN (NULL);
1848 mono_domain_set_internal_with_options (MonoDomain *domain, gboolean migrate_exception)
1850 MonoInternalThread *thread;
1852 if (mono_domain_get () == domain)
1855 SET_APPDOMAIN (domain);
1856 SET_APPCONTEXT (domain->default_context);
1858 if (migrate_exception) {
1859 thread = mono_thread_internal_current ();
1860 if (!thread->abort_exc)
1863 g_assert (thread->abort_exc->object.vtable->domain != domain);
1864 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
1865 g_assert (thread->abort_exc->object.vtable->domain == domain);
1870 * mono_domain_set_internal:
1871 * @domain: the new domain
1873 * Sets the current domain to @domain.
1876 mono_domain_set_internal (MonoDomain *domain)
1878 mono_domain_set_internal_with_options (domain, TRUE);
1882 mono_domain_foreach (MonoDomainFunc func, gpointer user_data)
1888 * Create a copy of the data to avoid calling the user callback
1889 * inside the lock because that could lead to deadlocks.
1890 * We can do this because this function is not perf. critical.
1892 mono_appdomains_lock ();
1893 size = appdomain_list_size;
1894 copy = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1895 memcpy (copy, appdomains_list, appdomain_list_size * sizeof (void*));
1896 mono_appdomains_unlock ();
1898 for (i = 0; i < size; ++i) {
1900 func (copy [i], user_data);
1903 mono_gc_free_fixed (copy);
1907 * mono_domain_assembly_open:
1908 * @domain: the application domain
1909 * @name: file name of the assembly
1911 * fixme: maybe we should integrate this with mono_assembly_open ??
1914 mono_domain_assembly_open (MonoDomain *domain, const char *name)
1916 MonoDomain *current;
1920 mono_domain_assemblies_lock (domain);
1921 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1923 if (strcmp (name, ass->aname.name) == 0) {
1924 mono_domain_assemblies_unlock (domain);
1928 mono_domain_assemblies_unlock (domain);
1930 if (domain != mono_domain_get ()) {
1931 current = mono_domain_get ();
1933 mono_domain_set (domain, FALSE);
1934 ass = mono_assembly_open (name, NULL);
1935 mono_domain_set (current, FALSE);
1937 ass = mono_assembly_open (name, NULL);
1944 unregister_vtable_reflection_type (MonoVTable *vtable)
1946 MonoObject *type = vtable->type;
1948 if (type->vtable->klass != mono_defaults.monotype_class)
1949 MONO_GC_UNREGISTER_ROOT_IF_MOVING (vtable->type);
1953 mono_domain_free (MonoDomain *domain, gboolean force)
1955 int code_size, code_alloc;
1959 if ((domain == mono_root_domain) && !force) {
1960 g_warning ("cant unload root domain");
1964 if (mono_dont_free_domains)
1967 mono_profiler_appdomain_event (domain, MONO_PROFILE_START_UNLOAD);
1969 mono_debug_domain_unload (domain);
1971 mono_appdomains_lock ();
1972 appdomains_list [domain->domain_id] = NULL;
1973 mono_appdomains_unlock ();
1975 /* must do this early as it accesses fields and types */
1976 if (domain->special_static_fields) {
1977 mono_alloc_special_static_data_free (domain->special_static_fields);
1978 g_hash_table_destroy (domain->special_static_fields);
1979 domain->special_static_fields = NULL;
1983 * We must destroy all these hash tables here because they
1984 * contain references to managed objects belonging to the
1985 * domain. Once we let the GC clear the domain there must be
1986 * no more such references, or we'll crash if a collection
1989 mono_g_hash_table_destroy (domain->ldstr_table);
1990 domain->ldstr_table = NULL;
1992 mono_g_hash_table_destroy (domain->env);
1995 if (domain->tlsrec_list) {
1996 mono_thread_destroy_domain_tls (domain);
1997 domain->tlsrec_list = NULL;
2000 mono_reflection_cleanup_domain (domain);
2002 /* This must be done before type_hash is freed */
2003 if (domain->class_vtable_array) {
2005 for (i = 0; i < domain->class_vtable_array->len; ++i)
2006 unregister_vtable_reflection_type (g_ptr_array_index (domain->class_vtable_array, i));
2009 if (domain->type_hash) {
2010 mono_g_hash_table_destroy (domain->type_hash);
2011 domain->type_hash = NULL;
2013 if (domain->type_init_exception_hash) {
2014 mono_g_hash_table_destroy (domain->type_init_exception_hash);
2015 domain->type_init_exception_hash = NULL;
2018 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2019 MonoAssembly *ass = tmp->data;
2020 mono_assembly_release_gc_roots (ass);
2023 /* Have to zero out reference fields since they will be invalidated by the clear_domain () call below */
2024 for (p = (gpointer*)&domain->MONO_DOMAIN_FIRST_OBJECT; p < (gpointer*)&domain->MONO_DOMAIN_FIRST_GC_TRACKED; ++p)
2027 /* This needs to be done before closing assemblies */
2028 mono_gc_clear_domain (domain);
2030 /* Close dynamic assemblies first, since they have no ref count */
2031 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2032 MonoAssembly *ass = tmp->data;
2033 if (!ass->image || !image_is_dynamic (ass->image))
2035 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading domain %s[%p], assembly %s[%p], ref_count=%d", domain->friendly_name, domain, ass->aname.name, ass, ass->ref_count);
2036 if (!mono_assembly_close_except_image_pools (ass))
2040 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2041 MonoAssembly *ass = tmp->data;
2044 if (!ass->image || image_is_dynamic (ass->image))
2046 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading domain %s[%p], assembly %s[%p], ref_count=%d", domain->friendly_name, domain, ass->aname.name, ass, ass->ref_count);
2047 if (!mono_assembly_close_except_image_pools (ass))
2051 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2052 MonoAssembly *ass = tmp->data;
2054 mono_assembly_close_finish (ass);
2056 g_slist_free (domain->domain_assemblies);
2057 domain->domain_assemblies = NULL;
2060 * Send this after the assemblies have been unloaded and the domain is still in a
2063 mono_profiler_appdomain_event (domain, MONO_PROFILE_END_UNLOAD);
2065 if (free_domain_hook)
2066 free_domain_hook (domain);
2068 /* FIXME: free delegate_hash_table when it's used */
2069 if (domain->search_path) {
2070 g_strfreev (domain->search_path);
2071 domain->search_path = NULL;
2073 domain->create_proxy_for_type_method = NULL;
2074 domain->private_invoke_method = NULL;
2075 domain->default_context = NULL;
2076 domain->out_of_memory_ex = NULL;
2077 domain->null_reference_ex = NULL;
2078 domain->stack_overflow_ex = NULL;
2079 domain->ephemeron_tombstone = NULL;
2080 domain->entry_assembly = NULL;
2082 g_free (domain->friendly_name);
2083 domain->friendly_name = NULL;
2084 g_ptr_array_free (domain->class_vtable_array, TRUE);
2085 domain->class_vtable_array = NULL;
2086 g_hash_table_destroy (domain->proxy_vtable_hash);
2087 domain->proxy_vtable_hash = NULL;
2088 if (domain->static_data_array) {
2089 mono_gc_free_fixed (domain->static_data_array);
2090 domain->static_data_array = NULL;
2092 mono_internal_hash_table_destroy (&domain->jit_code_hash);
2095 * There might still be jit info tables of this domain which
2096 * are not freed. Since the domain cannot be in use anymore,
2097 * this will free them.
2099 mono_thread_hazardous_try_free_all ();
2100 if (domain->aot_modules)
2101 jit_info_table_free (domain->aot_modules);
2102 g_assert (domain->num_jit_info_tables == 1);
2103 jit_info_table_free (domain->jit_info_table);
2104 domain->jit_info_table = NULL;
2105 g_assert (!domain->jit_info_free_queue);
2107 /* collect statistics */
2108 code_alloc = mono_code_manager_size (domain->code_mp, &code_size);
2109 total_domain_code_alloc += code_alloc;
2110 max_domain_code_alloc = MAX (max_domain_code_alloc, code_alloc);
2111 max_domain_code_size = MAX (max_domain_code_size, code_size);
2113 if (debug_domain_unload) {
2114 mono_mempool_invalidate (domain->mp);
2115 mono_code_manager_invalidate (domain->code_mp);
2117 #ifndef DISABLE_PERFCOUNTERS
2118 mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (domain->mp);
2120 mono_mempool_destroy (domain->mp);
2122 mono_code_manager_destroy (domain->code_mp);
2123 domain->code_mp = NULL;
2125 lock_free_mempool_free (domain->lock_free_mp);
2126 domain->lock_free_mp = NULL;
2128 g_hash_table_destroy (domain->finalizable_objects_hash);
2129 domain->finalizable_objects_hash = NULL;
2130 if (domain->method_rgctx_hash) {
2131 g_hash_table_destroy (domain->method_rgctx_hash);
2132 domain->method_rgctx_hash = NULL;
2134 if (domain->generic_virtual_cases) {
2135 g_hash_table_destroy (domain->generic_virtual_cases);
2136 domain->generic_virtual_cases = NULL;
2138 if (domain->generic_virtual_thunks) {
2139 g_hash_table_destroy (domain->generic_virtual_thunks);
2140 domain->generic_virtual_thunks = NULL;
2142 if (domain->ftnptrs_hash) {
2143 g_hash_table_destroy (domain->ftnptrs_hash);
2144 domain->ftnptrs_hash = NULL;
2147 mono_mutex_destroy (&domain->finalizable_objects_hash_lock);
2148 mono_mutex_destroy (&domain->assemblies_lock);
2149 mono_mutex_destroy (&domain->jit_code_hash_lock);
2150 mono_mutex_destroy (&domain->lock);
2151 domain->setup = NULL;
2153 mono_gc_deregister_root ((char*)&(domain->MONO_DOMAIN_FIRST_GC_TRACKED));
2155 /* FIXME: anything else required ? */
2157 mono_gc_free_fixed (domain);
2159 #ifndef DISABLE_PERFCOUNTERS
2160 mono_perfcounters->loader_appdomains--;
2163 if (domain == mono_root_domain)
2164 mono_root_domain = NULL;
2168 * mono_domain_get_id:
2171 * Returns: the a domain for a specific domain id.
2174 mono_domain_get_by_id (gint32 domainid)
2176 MonoDomain * domain;
2178 mono_appdomains_lock ();
2179 if (domainid < appdomain_list_size)
2180 domain = appdomains_list [domainid];
2183 mono_appdomains_unlock ();
2189 mono_domain_get_id (MonoDomain *domain)
2191 return domain->domain_id;
2195 * mono_domain_alloc:
2197 * LOCKING: Acquires the domain lock.
2200 mono_domain_alloc (MonoDomain *domain, guint size)
2204 mono_domain_lock (domain);
2205 #ifndef DISABLE_PERFCOUNTERS
2206 mono_perfcounters->loader_bytes += size;
2208 res = mono_mempool_alloc (domain->mp, size);
2209 mono_domain_unlock (domain);
2215 * mono_domain_alloc0:
2217 * LOCKING: Acquires the domain lock.
2220 mono_domain_alloc0 (MonoDomain *domain, guint size)
2224 mono_domain_lock (domain);
2225 #ifndef DISABLE_PERFCOUNTERS
2226 mono_perfcounters->loader_bytes += size;
2228 res = mono_mempool_alloc0 (domain->mp, size);
2229 mono_domain_unlock (domain);
2235 mono_domain_alloc0_lock_free (MonoDomain *domain, guint size)
2237 return lock_free_mempool_alloc0 (domain->lock_free_mp, size);
2241 * mono_domain_code_reserve:
2243 * LOCKING: Acquires the domain lock.
2246 mono_domain_code_reserve (MonoDomain *domain, int size)
2250 mono_domain_lock (domain);
2251 res = mono_code_manager_reserve (domain->code_mp, size);
2252 mono_domain_unlock (domain);
2258 * mono_domain_code_reserve_align:
2260 * LOCKING: Acquires the domain lock.
2263 mono_domain_code_reserve_align (MonoDomain *domain, int size, int alignment)
2267 mono_domain_lock (domain);
2268 res = mono_code_manager_reserve_align (domain->code_mp, size, alignment);
2269 mono_domain_unlock (domain);
2275 * mono_domain_code_commit:
2277 * LOCKING: Acquires the domain lock.
2280 mono_domain_code_commit (MonoDomain *domain, void *data, int size, int newsize)
2282 mono_domain_lock (domain);
2283 mono_code_manager_commit (domain->code_mp, data, size, newsize);
2284 mono_domain_unlock (domain);
2287 #if defined(__native_client_codegen__) && defined(__native_client__)
2289 * Given the temporary buffer (allocated by mono_domain_code_reserve) into which
2290 * we are generating code, return a pointer to the destination in the dynamic
2291 * code segment into which the code will be copied when mono_domain_code_commit
2293 * LOCKING: Acquires the domain lock.
2296 nacl_domain_get_code_dest (MonoDomain *domain, void *data)
2299 mono_domain_lock (domain);
2300 dest = nacl_code_manager_get_code_dest (domain->code_mp, data);
2301 mono_domain_unlock (domain);
2306 * Convenience function which calls mono_domain_code_commit to validate and copy
2307 * the code. The caller sets *buf_base and *buf_size to the start and size of
2308 * the buffer (allocated by mono_domain_code_reserve), and *code_end to the byte
2309 * after the last instruction byte. On return, *buf_base will point to the start
2310 * of the copied in the code segment, and *code_end will point after the end of
2314 nacl_domain_code_validate (MonoDomain *domain, guint8 **buf_base, int buf_size, guint8 **code_end)
2316 guint8 *tmp = nacl_domain_get_code_dest (domain, *buf_base);
2317 mono_domain_code_commit (domain, *buf_base, buf_size, *code_end - *buf_base);
2318 *code_end = tmp + (*code_end - *buf_base);
2324 /* no-op versions of Native Client functions */
2327 nacl_domain_get_code_dest (MonoDomain *domain, void *data)
2333 nacl_domain_code_validate (MonoDomain *domain, guint8 **buf_base, int buf_size, guint8 **code_end)
2340 * mono_domain_code_foreach:
2341 * Iterate over the code thunks of the code manager of @domain.
2343 * The @func callback MUST not take any locks. If it really needs to, it must respect
2344 * the locking rules of the runtime: http://www.mono-project.com/Mono:Runtime:Documentation:ThreadSafety
2345 * LOCKING: Acquires the domain lock.
2349 mono_domain_code_foreach (MonoDomain *domain, MonoCodeManagerFunc func, void *user_data)
2351 mono_domain_lock (domain);
2352 mono_code_manager_foreach (domain->code_mp, func, user_data);
2353 mono_domain_unlock (domain);
2358 mono_context_set (MonoAppContext * new_context)
2360 SET_APPCONTEXT (new_context);
2364 mono_context_get (void)
2366 return GET_APPCONTEXT ();
2369 /* LOCKING: the caller holds the lock for this domain */
2371 mono_domain_add_class_static_data (MonoDomain *domain, MonoClass *klass, gpointer data, guint32 *bitmap)
2373 /* The first entry in the array is the index of the next free slot
2374 * and the total size of the array
2377 if (domain->static_data_array) {
2378 int size = GPOINTER_TO_INT (domain->static_data_array [1]);
2379 next = GPOINTER_TO_INT (domain->static_data_array [0]);
2381 /* 'data' is allocated by alloc_fixed */
2382 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * (size * 2), MONO_GC_ROOT_DESCR_FOR_FIXED (size * 2));
2383 mono_gc_memmove_aligned (new_array, domain->static_data_array, sizeof (gpointer) * size);
2385 new_array [1] = GINT_TO_POINTER (size);
2386 mono_gc_free_fixed (domain->static_data_array);
2387 domain->static_data_array = new_array;
2391 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * size, MONO_GC_ROOT_DESCR_FOR_FIXED (size));
2393 new_array [0] = GINT_TO_POINTER (next);
2394 new_array [1] = GINT_TO_POINTER (size);
2395 domain->static_data_array = new_array;
2397 domain->static_data_array [next++] = data;
2398 domain->static_data_array [0] = GINT_TO_POINTER (next);
2402 mono_get_corlib (void)
2404 return mono_defaults.corlib;
2408 mono_get_object_class (void)
2410 return mono_defaults.object_class;
2414 mono_get_byte_class (void)
2416 return mono_defaults.byte_class;
2420 mono_get_void_class (void)
2422 return mono_defaults.void_class;
2426 mono_get_boolean_class (void)
2428 return mono_defaults.boolean_class;
2432 mono_get_sbyte_class (void)
2434 return mono_defaults.sbyte_class;
2438 mono_get_int16_class (void)
2440 return mono_defaults.int16_class;
2444 mono_get_uint16_class (void)
2446 return mono_defaults.uint16_class;
2450 mono_get_int32_class (void)
2452 return mono_defaults.int32_class;
2456 mono_get_uint32_class (void)
2458 return mono_defaults.uint32_class;
2462 mono_get_intptr_class (void)
2464 return mono_defaults.int_class;
2468 mono_get_uintptr_class (void)
2470 return mono_defaults.uint_class;
2474 mono_get_int64_class (void)
2476 return mono_defaults.int64_class;
2480 mono_get_uint64_class (void)
2482 return mono_defaults.uint64_class;
2486 mono_get_single_class (void)
2488 return mono_defaults.single_class;
2492 mono_get_double_class (void)
2494 return mono_defaults.double_class;
2498 mono_get_char_class (void)
2500 return mono_defaults.char_class;
2504 mono_get_string_class (void)
2506 return mono_defaults.string_class;
2510 mono_get_enum_class (void)
2512 return mono_defaults.enum_class;
2516 mono_get_array_class (void)
2518 return mono_defaults.array_class;
2522 mono_get_thread_class (void)
2524 return mono_defaults.thread_class;
2528 mono_get_exception_class (void)
2530 return mono_defaults.exception_class;
2534 static char* get_attribute_value (const gchar **attribute_names,
2535 const gchar **attribute_values,
2536 const char *att_name)
2539 for (n=0; attribute_names[n] != NULL; n++) {
2540 if (strcmp (attribute_names[n], att_name) == 0)
2541 return g_strdup (attribute_values[n]);
2546 static void start_element (GMarkupParseContext *context,
2547 const gchar *element_name,
2548 const gchar **attribute_names,
2549 const gchar **attribute_values,
2553 AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2555 if (strcmp (element_name, "configuration") == 0) {
2556 app_config->configuration_count++;
2559 if (strcmp (element_name, "startup") == 0) {
2560 app_config->startup_count++;
2564 if (app_config->configuration_count != 1 || app_config->startup_count != 1)
2567 if (strcmp (element_name, "requiredRuntime") == 0) {
2568 app_config->required_runtime = get_attribute_value (attribute_names, attribute_values, "version");
2569 } else if (strcmp (element_name, "supportedRuntime") == 0) {
2570 char *version = get_attribute_value (attribute_names, attribute_values, "version");
2571 app_config->supported_runtimes = g_slist_append (app_config->supported_runtimes, version);
2575 static void end_element (GMarkupParseContext *context,
2576 const gchar *element_name,
2580 AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2582 if (strcmp (element_name, "configuration") == 0) {
2583 app_config->configuration_count--;
2584 } else if (strcmp (element_name, "startup") == 0) {
2585 app_config->startup_count--;
2589 static const GMarkupParser
2598 static AppConfigInfo *
2599 app_config_parse (const char *exe_filename)
2601 AppConfigInfo *app_config;
2602 GMarkupParseContext *context;
2605 const char *bundled_config;
2606 char *config_filename;
2608 bundled_config = mono_config_string_for_assembly_file (exe_filename);
2610 if (bundled_config) {
2611 text = g_strdup (bundled_config);
2612 len = strlen (text);
2614 config_filename = g_strconcat (exe_filename, ".config", NULL);
2616 if (!g_file_get_contents (config_filename, &text, &len, NULL)) {
2617 g_free (config_filename);
2620 g_free (config_filename);
2623 app_config = g_new0 (AppConfigInfo, 1);
2625 context = g_markup_parse_context_new (&mono_parser, 0, app_config, NULL);
2626 if (g_markup_parse_context_parse (context, text, len, NULL)) {
2627 g_markup_parse_context_end_parse (context, NULL);
2629 g_markup_parse_context_free (context);
2635 app_config_free (AppConfigInfo* app_config)
2638 GSList *list = app_config->supported_runtimes;
2639 while (list != NULL) {
2640 rt = (char*)list->data;
2642 list = g_slist_next (list);
2644 g_slist_free (app_config->supported_runtimes);
2645 g_free (app_config->required_runtime);
2646 g_free (app_config);
2650 static const MonoRuntimeInfo*
2651 get_runtime_by_version (const char *version)
2654 int max = G_N_ELEMENTS (supported_runtimes);
2660 for (n=0; n<max; n++) {
2661 if (strcmp (version, supported_runtimes[n].runtime_version) == 0)
2662 return &supported_runtimes[n];
2665 vlen = strlen (version);
2666 if (vlen >= 4 && version [1] - '0' >= 4) {
2667 for (n=0; n<max; n++) {
2668 if (strncmp (version, supported_runtimes[n].runtime_version, 4) == 0)
2669 return &supported_runtimes[n];
2677 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes)
2679 AppConfigInfo* app_config;
2681 const MonoRuntimeInfo* runtime = NULL;
2682 MonoImage *image = NULL;
2684 app_config = app_config_parse (exe_file);
2686 if (app_config != NULL) {
2687 /* Check supportedRuntime elements, if none is supported, fail.
2688 * If there are no such elements, look for a requiredRuntime element.
2690 if (app_config->supported_runtimes != NULL) {
2692 GSList *list = app_config->supported_runtimes;
2693 while (list != NULL) {
2694 version = (char*) list->data;
2695 runtime = get_runtime_by_version (version);
2696 if (runtime != NULL)
2697 runtimes [n++] = runtime;
2698 list = g_slist_next (list);
2700 runtimes [n] = NULL;
2701 app_config_free (app_config);
2705 /* Check the requiredRuntime element. This is for 1.0 apps only. */
2706 if (app_config->required_runtime != NULL) {
2707 runtimes [0] = get_runtime_by_version (app_config->required_runtime);
2708 runtimes [1] = NULL;
2709 app_config_free (app_config);
2712 app_config_free (app_config);
2715 /* Look for a runtime with the exact version */
2716 image = mono_assembly_open_from_bundle (exe_file, NULL, FALSE);
2719 image = mono_image_open (exe_file, NULL);
2721 if (image == NULL) {
2722 /* The image is wrong or the file was not found. In this case return
2723 * a default runtime and leave to the initialization method the work of
2724 * reporting the error.
2726 runtimes [0] = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
2727 runtimes [1] = NULL;
2733 runtimes [0] = get_runtime_by_version (image->version);
2734 runtimes [1] = NULL;
2739 * mono_get_runtime_info:
2741 * Returns: the version of the current runtime instance.
2743 const MonoRuntimeInfo*
2744 mono_get_runtime_info (void)
2746 return current_runtime;
2750 mono_debugger_check_runtime_version (const char *filename)
2752 const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
2753 const MonoRuntimeInfo *rinfo;
2756 get_runtimes_from_exe (filename, &image, runtimes);
2757 rinfo = runtimes [0];
2760 return g_strdup_printf ("Cannot get runtime version from assembly `%s'", filename);
2762 if (rinfo != current_runtime)
2763 return g_strdup_printf ("The Mono Debugger is currently using the `%s' runtime, but "
2764 "the assembly `%s' requires version `%s'", current_runtime->runtime_version,
2765 filename, rinfo->runtime_version);
2771 * mono_framework_version:
2773 * Return the major version of the framework curently executing.
2776 mono_framework_version (void)
2778 return current_runtime->framework_version [0] - '0';
2782 mono_enable_debug_domain_unload (gboolean enable)
2784 debug_domain_unload = enable;
2787 MonoAotCacheConfig *
2788 mono_get_aot_cache_config (void)
2790 return &aot_cache_config;