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_size (MonoJitInfoFlags flags, int num_clauses, int num_holes)
896 int size = MONO_SIZEOF_JIT_INFO;
898 size += num_clauses * sizeof (MonoJitExceptionInfo);
899 if (flags & JIT_INFO_HAS_CAS_INFO)
900 size += sizeof (MonoMethodCasInfo);
901 if (flags & JIT_INFO_HAS_GENERIC_JIT_INFO)
902 size += sizeof (MonoGenericJitInfo);
903 if (flags & JIT_INFO_HAS_TRY_BLOCK_HOLES)
904 size += sizeof (MonoTryBlockHoleTableJitInfo) + num_holes * sizeof (MonoTryBlockHoleJitInfo);
905 if (flags & JIT_INFO_HAS_ARCH_EH_INFO)
906 size += sizeof (MonoArchEHJitInfo);
911 mono_jit_info_init (MonoJitInfo *ji, MonoMethod *method, guint8 *code, int code_size,
912 MonoJitInfoFlags flags, int num_clauses, int num_holes)
914 ji->d.method = method;
915 ji->code_start = code;
916 ji->code_size = code_size;
917 ji->num_clauses = num_clauses;
918 if (flags & JIT_INFO_HAS_CAS_INFO)
919 ji->has_cas_info = 1;
920 if (flags & JIT_INFO_HAS_GENERIC_JIT_INFO)
921 ji->has_generic_jit_info = 1;
922 if (flags & JIT_INFO_HAS_TRY_BLOCK_HOLES)
923 ji->has_try_block_holes = 1;
924 if (flags & JIT_INFO_HAS_ARCH_EH_INFO)
925 ji->has_arch_eh_info = 1;
929 mono_jit_info_get_code_start (MonoJitInfo* ji)
931 return ji->code_start;
935 mono_jit_info_get_code_size (MonoJitInfo* ji)
937 return ji->code_size;
941 mono_jit_info_get_method (MonoJitInfo* ji)
943 g_assert (!ji->async);
948 jit_info_key_extract (gpointer value)
950 MonoJitInfo *info = (MonoJitInfo*)value;
952 return info->d.method;
956 jit_info_next_value (gpointer value)
958 MonoJitInfo *info = (MonoJitInfo*)value;
960 return (gpointer*)&info->next_jit_code_hash;
964 mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
966 mono_internal_hash_table_init (jit_code_hash,
967 mono_aligned_addr_hash,
968 jit_info_key_extract,
969 jit_info_next_value);
973 mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
975 if (ji->has_generic_jit_info)
976 return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
982 * mono_jit_info_get_generic_sharing_context:
985 * Returns the jit info's generic sharing context, or NULL if it
988 MonoGenericSharingContext*
989 mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
991 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
994 return gi->generic_sharing_context;
1000 * mono_jit_info_set_generic_sharing_context:
1002 * @gsctx: a generic sharing context
1004 * Sets the jit info's generic sharing context. The jit info must
1005 * have memory allocated for the context.
1008 mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
1010 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
1014 gi->generic_sharing_context = gsctx;
1017 MonoTryBlockHoleTableJitInfo*
1018 mono_jit_info_get_try_block_hole_table_info (MonoJitInfo *ji)
1020 if (ji->has_try_block_holes) {
1021 char *ptr = (char*)&ji->clauses [ji->num_clauses];
1022 if (ji->has_generic_jit_info)
1023 ptr += sizeof (MonoGenericJitInfo);
1024 return (MonoTryBlockHoleTableJitInfo*)ptr;
1031 try_block_hole_table_size (MonoJitInfo *ji)
1033 MonoTryBlockHoleTableJitInfo *table;
1035 table = mono_jit_info_get_try_block_hole_table_info (ji);
1037 return sizeof (MonoTryBlockHoleTableJitInfo) + table->num_holes * sizeof (MonoTryBlockHoleJitInfo);
1041 mono_jit_info_get_arch_eh_info (MonoJitInfo *ji)
1043 if (ji->has_arch_eh_info) {
1044 char *ptr = (char*)&ji->clauses [ji->num_clauses];
1045 if (ji->has_generic_jit_info)
1046 ptr += sizeof (MonoGenericJitInfo);
1047 if (ji->has_try_block_holes)
1048 ptr += try_block_hole_table_size (ji);
1049 return (MonoArchEHJitInfo*)ptr;
1056 mono_jit_info_get_cas_info (MonoJitInfo *ji)
1058 if (ji->has_cas_info) {
1059 char *ptr = (char*)&ji->clauses [ji->num_clauses];
1060 if (ji->has_generic_jit_info)
1061 ptr += sizeof (MonoGenericJitInfo);
1062 if (ji->has_try_block_holes)
1063 ptr += try_block_hole_table_size (ji);
1064 if (ji->has_arch_eh_info)
1065 ptr += sizeof (MonoArchEHJitInfo);
1066 return (MonoMethodCasInfo*)ptr;
1072 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
1073 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
1075 static LockFreeMempool*
1076 lock_free_mempool_new (void)
1078 return g_new0 (LockFreeMempool, 1);
1082 lock_free_mempool_free (LockFreeMempool *mp)
1084 LockFreeMempoolChunk *chunk, *next;
1089 mono_vfree (chunk, mono_pagesize ());
1096 * This is async safe
1098 static LockFreeMempoolChunk*
1099 lock_free_mempool_chunk_new (LockFreeMempool *mp, int len)
1101 LockFreeMempoolChunk *chunk, *prev;
1104 size = mono_pagesize ();
1105 while (size - sizeof (LockFreeMempoolChunk) < len)
1106 size += mono_pagesize ();
1107 chunk = mono_valloc (0, size, MONO_MMAP_READ|MONO_MMAP_WRITE);
1109 chunk->mem = ALIGN_PTR_TO ((char*)chunk + sizeof (LockFreeMempoolChunk), 16);
1110 chunk->size = ((char*)chunk + size) - (char*)chunk->mem;
1113 /* Add to list of chunks lock-free */
1116 if (InterlockedCompareExchangePointer ((volatile gpointer*)&mp->chunks, chunk, prev) == prev)
1125 * This is async safe
1128 lock_free_mempool_alloc0 (LockFreeMempool *mp, guint size)
1130 LockFreeMempoolChunk *chunk;
1134 // FIXME: Free the allocator
1136 size = ALIGN_TO (size, 8);
1137 chunk = mp->current;
1139 chunk = lock_free_mempool_chunk_new (mp, size);
1140 mono_memory_barrier ();
1142 mp->current = chunk;
1145 /* The code below is lock-free, 'chunk' is shared state */
1146 oldpos = InterlockedExchangeAdd (&chunk->pos, size);
1147 if (oldpos + size > chunk->size) {
1148 chunk = lock_free_mempool_chunk_new (mp, size);
1149 g_assert (chunk->pos + size <= chunk->size);
1152 mono_memory_barrier ();
1153 mp->current = chunk;
1155 res = (char*)chunk->mem + oldpos;
1162 mono_install_create_domain_hook (MonoCreateDomainFunc func)
1164 create_domain_hook = func;
1168 mono_install_free_domain_hook (MonoFreeDomainFunc func)
1170 free_domain_hook = func;
1174 * mono_string_equal:
1175 * @s1: First string to compare
1176 * @s2: Second string to compare
1178 * Returns FALSE if the strings differ.
1181 mono_string_equal (MonoString *s1, MonoString *s2)
1183 int l1 = mono_string_length (s1);
1184 int l2 = mono_string_length (s2);
1191 return memcmp (mono_string_chars (s1), mono_string_chars (s2), l1 * 2) == 0;
1196 * @s: the string to hash
1198 * Returns the hash for the string.
1201 mono_string_hash (MonoString *s)
1203 const guint16 *p = mono_string_chars (s);
1204 int i, len = mono_string_length (s);
1207 for (i = 0; i < len; i++) {
1208 h = (h << 5) - h + *p;
1216 mono_ptrarray_equal (gpointer *s1, gpointer *s2)
1218 int len = GPOINTER_TO_INT (s1 [0]);
1219 if (len != GPOINTER_TO_INT (s2 [0]))
1222 return memcmp (s1 + 1, s2 + 1, len * sizeof(gpointer)) == 0;
1226 mono_ptrarray_hash (gpointer *s)
1229 int len = GPOINTER_TO_INT (s [0]);
1232 for (i = 1; i < len; i++)
1233 hash += GPOINTER_TO_UINT (s [i]);
1239 * Allocate an id for domain and set domain->domain_id.
1240 * LOCKING: must be called while holding appdomains_mutex.
1241 * We try to assign low numbers to the domain, so it can be used
1242 * as an index in data tables to lookup domain-specific info
1243 * with minimal memory overhead. We also try not to reuse the
1244 * same id too quickly (to help debugging).
1247 domain_id_alloc (MonoDomain *domain)
1250 if (!appdomains_list) {
1251 appdomain_list_size = 2;
1252 appdomains_list = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1254 for (i = appdomain_next; i < appdomain_list_size; ++i) {
1255 if (!appdomains_list [i]) {
1261 for (i = 0; i < appdomain_next; ++i) {
1262 if (!appdomains_list [i]) {
1269 MonoDomain **new_list;
1270 int new_size = appdomain_list_size * 2;
1271 if (new_size >= (1 << 16))
1272 g_assert_not_reached ();
1273 id = appdomain_list_size;
1274 new_list = mono_gc_alloc_fixed (new_size * sizeof (void*), NULL);
1275 memcpy (new_list, appdomains_list, appdomain_list_size * sizeof (void*));
1276 mono_gc_free_fixed (appdomains_list);
1277 appdomains_list = new_list;
1278 appdomain_list_size = new_size;
1280 domain->domain_id = id;
1281 appdomains_list [id] = domain;
1283 if (appdomain_next > appdomain_list_size)
1288 static gsize domain_gc_bitmap [sizeof(MonoDomain)/4/32 + 1];
1289 static gpointer domain_gc_desc = NULL;
1290 static guint32 domain_shadow_serial = 0L;
1293 mono_domain_create (void)
1296 guint32 shadow_serial;
1298 mono_appdomains_lock ();
1299 shadow_serial = domain_shadow_serial++;
1301 if (!domain_gc_desc) {
1302 unsigned int i, bit = 0;
1303 for (i = G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_OBJECT); i < G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_GC_TRACKED); i += sizeof (gpointer)) {
1304 bit = i / sizeof (gpointer);
1305 domain_gc_bitmap [bit / 32] |= (gsize) 1 << (bit % 32);
1307 domain_gc_desc = mono_gc_make_descr_from_bitmap ((gsize*)domain_gc_bitmap, bit + 1);
1309 mono_appdomains_unlock ();
1311 #ifdef HAVE_BOEHM_GC
1313 * Boehm doesn't like roots inside GC allocated objects, and alloc_fixed returns
1314 * a GC_MALLOC-ed object, contrary to the api docs. This causes random crashes when
1315 * running the corlib test suite.
1316 * To solve this, we pass a NULL descriptor, and don't register roots.
1318 domain = mono_gc_alloc_fixed (sizeof (MonoDomain), NULL);
1320 domain = mono_gc_alloc_fixed (sizeof (MonoDomain), domain_gc_desc);
1321 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);
1323 domain->shadow_serial = shadow_serial;
1324 domain->domain = NULL;
1325 domain->setup = NULL;
1326 domain->friendly_name = NULL;
1327 domain->search_path = NULL;
1329 mono_profiler_appdomain_event (domain, MONO_PROFILE_START_LOAD);
1331 domain->mp = mono_mempool_new ();
1332 domain->code_mp = mono_code_manager_new ();
1333 domain->lock_free_mp = lock_free_mempool_new ();
1334 domain->env = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1335 domain->domain_assemblies = NULL;
1336 domain->assembly_bindings = NULL;
1337 domain->assembly_bindings_parsed = FALSE;
1338 domain->class_vtable_array = g_ptr_array_new ();
1339 domain->proxy_vtable_hash = g_hash_table_new ((GHashFunc)mono_ptrarray_hash, (GCompareFunc)mono_ptrarray_equal);
1340 domain->static_data_array = NULL;
1341 mono_jit_code_hash_init (&domain->jit_code_hash);
1342 domain->ldstr_table = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1343 domain->num_jit_info_tables = 1;
1344 domain->jit_info_table = jit_info_table_new (domain);
1345 domain->jit_info_free_queue = NULL;
1346 domain->finalizable_objects_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1347 domain->ftnptrs_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1349 mono_mutex_init_recursive (&domain->lock);
1350 mono_mutex_init_recursive (&domain->assemblies_lock);
1351 mono_mutex_init_recursive (&domain->jit_code_hash_lock);
1352 mono_mutex_init_recursive (&domain->finalizable_objects_hash_lock);
1354 domain->method_rgctx_hash = NULL;
1356 mono_appdomains_lock ();
1357 domain_id_alloc (domain);
1358 mono_appdomains_unlock ();
1360 #ifndef DISABLE_PERFCOUNTERS
1361 mono_perfcounters->loader_appdomains++;
1362 mono_perfcounters->loader_total_appdomains++;
1365 mono_debug_domain_create (domain);
1367 if (create_domain_hook)
1368 create_domain_hook (domain);
1370 mono_profiler_appdomain_loaded (domain, MONO_PROFILE_OK);
1376 * mono_init_internal:
1378 * Creates the initial application domain and initializes the mono_defaults
1380 * This function is guaranteed to not run any IL code.
1381 * If exe_filename is not NULL, the method will determine the required runtime
1382 * from the exe configuration file or the version PE field.
1383 * If runtime_version is not NULL, that runtime version will be used.
1384 * Either exe_filename or runtime_version must be provided.
1386 * Returns: the initial domain.
1389 mono_init_internal (const char *filename, const char *exe_filename, const char *runtime_version)
1391 static MonoDomain *domain = NULL;
1392 MonoAssembly *ass = NULL;
1393 MonoImageOpenStatus status = MONO_IMAGE_OK;
1394 const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
1397 #ifdef DEBUG_DOMAIN_UNLOAD
1398 debug_domain_unload = TRUE;
1402 g_assert_not_reached ();
1405 /* Avoid system error message boxes. */
1406 SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1413 #ifndef DISABLE_PERFCOUNTERS
1414 mono_perfcounters_init ();
1417 mono_counters_register ("Max native code in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_size);
1418 mono_counters_register ("Max code space allocated in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_alloc);
1419 mono_counters_register ("Total code space allocated", MONO_COUNTER_INT|MONO_COUNTER_JIT, &total_domain_code_alloc);
1421 mono_gc_base_init ();
1423 MONO_FAST_TLS_INIT (tls_appdomain);
1424 mono_native_tls_alloc (&appdomain_thread_id, NULL);
1426 mono_mutex_init_recursive (&appdomains_mutex);
1428 mono_metadata_init ();
1429 mono_images_init ();
1430 mono_assemblies_init ();
1431 mono_classes_init ();
1432 mono_loader_init ();
1433 mono_reflection_init ();
1434 mono_runtime_init_tls ();
1436 /* FIXME: When should we release this memory? */
1437 MONO_GC_REGISTER_ROOT_FIXED (appdomains_list);
1439 domain = mono_domain_create ();
1440 mono_root_domain = domain;
1442 SET_APPDOMAIN (domain);
1444 /* Get a list of runtimes supported by the exe */
1445 if (exe_filename != NULL) {
1447 * This function will load the exe file as a MonoImage. We need to close it, but
1448 * that would mean it would be reloaded later. So instead, we save it to
1449 * exe_image, and close it during shutdown.
1451 get_runtimes_from_exe (exe_filename, &exe_image, runtimes);
1454 exe_image = mono_assembly_open_from_bundle (exe_filename, NULL, FALSE);
1456 exe_image = mono_image_open (exe_filename, NULL);
1458 mono_fixup_exe_image (exe_image);
1460 } else if (runtime_version != NULL) {
1461 runtimes [0] = get_runtime_by_version (runtime_version);
1462 runtimes [1] = NULL;
1465 if (runtimes [0] == NULL) {
1466 const MonoRuntimeInfo *default_runtime = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
1467 runtimes [0] = default_runtime;
1468 runtimes [1] = NULL;
1469 g_print ("WARNING: The runtime version supported by this application is unavailable.\n");
1470 g_print ("Using default runtime: %s\n", default_runtime->runtime_version);
1473 /* The selected runtime will be the first one for which there is a mscrolib.dll */
1474 for (n = 0; runtimes [n] != NULL && ass == NULL; n++) {
1475 current_runtime = runtimes [n];
1476 ass = mono_assembly_load_corlib (current_runtime, &status);
1477 if (status != MONO_IMAGE_OK && status != MONO_IMAGE_ERROR_ERRNO)
1482 if ((status != MONO_IMAGE_OK) || (ass == NULL)) {
1484 case MONO_IMAGE_ERROR_ERRNO: {
1485 char *corlib_file = g_build_filename (mono_assembly_getrootdir (), "mono", current_runtime->framework_version, "mscorlib.dll", NULL);
1486 g_print ("The assembly mscorlib.dll was not found or could not be loaded.\n");
1487 g_print ("It should have been installed in the `%s' directory.\n", corlib_file);
1488 g_free (corlib_file);
1491 case MONO_IMAGE_IMAGE_INVALID:
1492 g_print ("The file %s/mscorlib.dll is an invalid CIL image\n",
1493 mono_assembly_getrootdir ());
1495 case MONO_IMAGE_MISSING_ASSEMBLYREF:
1496 g_print ("Missing assembly reference in %s/mscorlib.dll\n",
1497 mono_assembly_getrootdir ());
1500 /* to suppress compiler warning */
1506 mono_defaults.corlib = mono_assembly_get_image (ass);
1508 mono_defaults.object_class = mono_class_from_name (
1509 mono_defaults.corlib, "System", "Object");
1510 g_assert (mono_defaults.object_class != 0);
1512 mono_defaults.void_class = mono_class_from_name (
1513 mono_defaults.corlib, "System", "Void");
1514 g_assert (mono_defaults.void_class != 0);
1516 mono_defaults.boolean_class = mono_class_from_name (
1517 mono_defaults.corlib, "System", "Boolean");
1518 g_assert (mono_defaults.boolean_class != 0);
1520 mono_defaults.byte_class = mono_class_from_name (
1521 mono_defaults.corlib, "System", "Byte");
1522 g_assert (mono_defaults.byte_class != 0);
1524 mono_defaults.sbyte_class = mono_class_from_name (
1525 mono_defaults.corlib, "System", "SByte");
1526 g_assert (mono_defaults.sbyte_class != 0);
1528 mono_defaults.int16_class = mono_class_from_name (
1529 mono_defaults.corlib, "System", "Int16");
1530 g_assert (mono_defaults.int16_class != 0);
1532 mono_defaults.uint16_class = mono_class_from_name (
1533 mono_defaults.corlib, "System", "UInt16");
1534 g_assert (mono_defaults.uint16_class != 0);
1536 mono_defaults.int32_class = mono_class_from_name (
1537 mono_defaults.corlib, "System", "Int32");
1538 g_assert (mono_defaults.int32_class != 0);
1540 mono_defaults.uint32_class = mono_class_from_name (
1541 mono_defaults.corlib, "System", "UInt32");
1542 g_assert (mono_defaults.uint32_class != 0);
1544 mono_defaults.uint_class = mono_class_from_name (
1545 mono_defaults.corlib, "System", "UIntPtr");
1546 g_assert (mono_defaults.uint_class != 0);
1548 mono_defaults.int_class = mono_class_from_name (
1549 mono_defaults.corlib, "System", "IntPtr");
1550 g_assert (mono_defaults.int_class != 0);
1552 mono_defaults.int64_class = mono_class_from_name (
1553 mono_defaults.corlib, "System", "Int64");
1554 g_assert (mono_defaults.int64_class != 0);
1556 mono_defaults.uint64_class = mono_class_from_name (
1557 mono_defaults.corlib, "System", "UInt64");
1558 g_assert (mono_defaults.uint64_class != 0);
1560 mono_defaults.single_class = mono_class_from_name (
1561 mono_defaults.corlib, "System", "Single");
1562 g_assert (mono_defaults.single_class != 0);
1564 mono_defaults.double_class = mono_class_from_name (
1565 mono_defaults.corlib, "System", "Double");
1566 g_assert (mono_defaults.double_class != 0);
1568 mono_defaults.char_class = mono_class_from_name (
1569 mono_defaults.corlib, "System", "Char");
1570 g_assert (mono_defaults.char_class != 0);
1572 mono_defaults.string_class = mono_class_from_name (
1573 mono_defaults.corlib, "System", "String");
1574 g_assert (mono_defaults.string_class != 0);
1576 mono_defaults.enum_class = mono_class_from_name (
1577 mono_defaults.corlib, "System", "Enum");
1578 g_assert (mono_defaults.enum_class != 0);
1580 mono_defaults.array_class = mono_class_from_name (
1581 mono_defaults.corlib, "System", "Array");
1582 g_assert (mono_defaults.array_class != 0);
1584 mono_defaults.delegate_class = mono_class_from_name (
1585 mono_defaults.corlib, "System", "Delegate");
1586 g_assert (mono_defaults.delegate_class != 0 );
1588 mono_defaults.multicastdelegate_class = mono_class_from_name (
1589 mono_defaults.corlib, "System", "MulticastDelegate");
1590 g_assert (mono_defaults.multicastdelegate_class != 0 );
1592 mono_defaults.asyncresult_class = mono_class_from_name (
1593 mono_defaults.corlib, "System.Runtime.Remoting.Messaging",
1595 g_assert (mono_defaults.asyncresult_class != 0 );
1597 mono_defaults.manualresetevent_class = mono_class_from_name (
1598 mono_defaults.corlib, "System.Threading", "ManualResetEvent");
1599 g_assert (mono_defaults.manualresetevent_class != 0 );
1601 mono_defaults.typehandle_class = mono_class_from_name (
1602 mono_defaults.corlib, "System", "RuntimeTypeHandle");
1603 g_assert (mono_defaults.typehandle_class != 0);
1605 mono_defaults.methodhandle_class = mono_class_from_name (
1606 mono_defaults.corlib, "System", "RuntimeMethodHandle");
1607 g_assert (mono_defaults.methodhandle_class != 0);
1609 mono_defaults.fieldhandle_class = mono_class_from_name (
1610 mono_defaults.corlib, "System", "RuntimeFieldHandle");
1611 g_assert (mono_defaults.fieldhandle_class != 0);
1613 mono_defaults.systemtype_class = mono_class_from_name (
1614 mono_defaults.corlib, "System", "Type");
1615 g_assert (mono_defaults.systemtype_class != 0);
1617 mono_defaults.monotype_class = mono_class_from_name (
1618 mono_defaults.corlib, "System", "MonoType");
1619 g_assert (mono_defaults.monotype_class != 0);
1621 mono_defaults.exception_class = mono_class_from_name (
1622 mono_defaults.corlib, "System", "Exception");
1623 g_assert (mono_defaults.exception_class != 0);
1625 mono_defaults.threadabortexception_class = mono_class_from_name (
1626 mono_defaults.corlib, "System.Threading", "ThreadAbortException");
1627 g_assert (mono_defaults.threadabortexception_class != 0);
1629 mono_defaults.thread_class = mono_class_from_name (
1630 mono_defaults.corlib, "System.Threading", "Thread");
1631 g_assert (mono_defaults.thread_class != 0);
1633 mono_defaults.internal_thread_class = mono_class_from_name (
1634 mono_defaults.corlib, "System.Threading", "InternalThread");
1635 if (!mono_defaults.internal_thread_class) {
1636 /* This can happen with an old mscorlib */
1637 fprintf (stderr, "Corlib too old for this runtime.\n");
1638 fprintf (stderr, "Loaded from: %s\n",
1639 mono_defaults.corlib? mono_image_get_filename (mono_defaults.corlib): "unknown");
1643 mono_defaults.appdomain_class = mono_class_from_name (
1644 mono_defaults.corlib, "System", "AppDomain");
1645 g_assert (mono_defaults.appdomain_class != 0);
1647 #ifndef DISABLE_REMOTING
1648 mono_defaults.transparent_proxy_class = mono_class_from_name (
1649 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "TransparentProxy");
1650 g_assert (mono_defaults.transparent_proxy_class != 0);
1652 mono_defaults.real_proxy_class = mono_class_from_name (
1653 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "RealProxy");
1654 g_assert (mono_defaults.real_proxy_class != 0);
1656 mono_defaults.marshalbyrefobject_class = mono_class_from_name (
1657 mono_defaults.corlib, "System", "MarshalByRefObject");
1658 g_assert (mono_defaults.marshalbyrefobject_class != 0);
1660 mono_defaults.iremotingtypeinfo_class = mono_class_from_name (
1661 mono_defaults.corlib, "System.Runtime.Remoting", "IRemotingTypeInfo");
1662 g_assert (mono_defaults.iremotingtypeinfo_class != 0);
1665 mono_defaults.mono_method_message_class = mono_class_from_name (
1666 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", "MonoMethodMessage");
1667 g_assert (mono_defaults.mono_method_message_class != 0);
1669 mono_defaults.field_info_class = mono_class_from_name (
1670 mono_defaults.corlib, "System.Reflection", "FieldInfo");
1671 g_assert (mono_defaults.field_info_class != 0);
1673 mono_defaults.method_info_class = mono_class_from_name (
1674 mono_defaults.corlib, "System.Reflection", "MethodInfo");
1675 g_assert (mono_defaults.method_info_class != 0);
1677 mono_defaults.stringbuilder_class = mono_class_from_name (
1678 mono_defaults.corlib, "System.Text", "StringBuilder");
1679 g_assert (mono_defaults.stringbuilder_class != 0);
1681 mono_defaults.math_class = mono_class_from_name (
1682 mono_defaults.corlib, "System", "Math");
1683 g_assert (mono_defaults.math_class != 0);
1685 mono_defaults.stack_frame_class = mono_class_from_name (
1686 mono_defaults.corlib, "System.Diagnostics", "StackFrame");
1687 g_assert (mono_defaults.stack_frame_class != 0);
1689 mono_defaults.stack_trace_class = mono_class_from_name (
1690 mono_defaults.corlib, "System.Diagnostics", "StackTrace");
1691 g_assert (mono_defaults.stack_trace_class != 0);
1693 mono_defaults.marshal_class = mono_class_from_name (
1694 mono_defaults.corlib, "System.Runtime.InteropServices", "Marshal");
1695 g_assert (mono_defaults.marshal_class != 0);
1697 mono_defaults.typed_reference_class = mono_class_from_name (
1698 mono_defaults.corlib, "System", "TypedReference");
1699 g_assert (mono_defaults.typed_reference_class != 0);
1701 mono_defaults.argumenthandle_class = mono_class_from_name (
1702 mono_defaults.corlib, "System", "RuntimeArgumentHandle");
1703 g_assert (mono_defaults.argumenthandle_class != 0);
1705 mono_defaults.monitor_class = mono_class_from_name (
1706 mono_defaults.corlib, "System.Threading", "Monitor");
1707 g_assert (mono_defaults.monitor_class != 0);
1709 mono_defaults.runtimesecurityframe_class = mono_class_from_name (
1710 mono_defaults.corlib, "System.Security", "RuntimeSecurityFrame");
1712 mono_defaults.executioncontext_class = mono_class_from_name (
1713 mono_defaults.corlib, "System.Threading", "ExecutionContext");
1715 mono_defaults.internals_visible_class = mono_class_from_name (
1716 mono_defaults.corlib, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute");
1718 mono_defaults.critical_finalizer_object = mono_class_from_name (
1719 mono_defaults.corlib, "System.Runtime.ConstrainedExecution", "CriticalFinalizerObject");
1722 * mscorlib needs a little help, only now it can load its friends list (after we have
1723 * loaded the InternalsVisibleToAttribute), load it now
1725 mono_assembly_load_friends (ass);
1727 mono_defaults.safehandle_class = mono_class_from_name (
1728 mono_defaults.corlib, "System.Runtime.InteropServices", "SafeHandle");
1730 mono_defaults.handleref_class = mono_class_from_name (
1731 mono_defaults.corlib, "System.Runtime.InteropServices", "HandleRef");
1733 mono_defaults.attribute_class = mono_class_from_name (
1734 mono_defaults.corlib, "System", "Attribute");
1736 mono_defaults.customattribute_data_class = mono_class_from_name (
1737 mono_defaults.corlib, "System.Reflection", "CustomAttributeData");
1739 /* these are initialized lazily when COM features are used */
1741 mono_class_init (mono_defaults.array_class);
1742 mono_defaults.generic_nullable_class = mono_class_from_name (
1743 mono_defaults.corlib, "System", "Nullable`1");
1744 mono_defaults.generic_ilist_class = mono_class_from_name (
1745 mono_defaults.corlib, "System.Collections.Generic", "IList`1");
1746 mono_defaults.generic_ireadonlylist_class = mono_class_from_name (
1747 mono_defaults.corlib, "System.Collections.Generic", "IReadOnlyList`1");
1749 domain->friendly_name = g_path_get_basename (filename);
1751 _mono_debug_init_corlib (domain);
1759 * Creates the initial application domain and initializes the mono_defaults
1761 * This function is guaranteed to not run any IL code.
1762 * The runtime is initialized using the default runtime version.
1764 * Returns: the initial domain.
1767 mono_init (const char *domain_name)
1769 return mono_init_internal (domain_name, NULL, DEFAULT_RUNTIME_VERSION);
1773 * mono_init_from_assembly:
1774 * @domain_name: name to give to the initial domain
1775 * @filename: filename to load on startup
1777 * Used by the runtime, users should use mono_jit_init instead.
1779 * Creates the initial application domain and initializes the mono_defaults
1781 * This function is guaranteed to not run any IL code.
1782 * The runtime is initialized using the runtime version required by the
1783 * provided executable. The version is determined by looking at the exe
1784 * configuration file and the version PE field)
1786 * Returns: the initial domain.
1789 mono_init_from_assembly (const char *domain_name, const char *filename)
1791 return mono_init_internal (domain_name, filename, NULL);
1795 * mono_init_version:
1797 * Used by the runtime, users should use mono_jit_init instead.
1799 * Creates the initial application domain and initializes the mono_defaults
1802 * This function is guaranteed to not run any IL code.
1803 * The runtime is initialized using the provided rutime version.
1805 * Returns: the initial domain.
1808 mono_init_version (const char *domain_name, const char *version)
1810 return mono_init_internal (domain_name, NULL, version);
1816 * Cleans up all metadata modules.
1821 mono_close_exe_image ();
1823 mono_defaults.corlib = NULL;
1825 mono_config_cleanup ();
1826 mono_loader_cleanup ();
1827 mono_classes_cleanup ();
1828 mono_assemblies_cleanup ();
1829 mono_images_cleanup ();
1830 mono_debug_cleanup ();
1831 mono_metadata_cleanup ();
1833 mono_native_tls_free (appdomain_thread_id);
1834 mono_mutex_destroy (&appdomains_mutex);
1842 mono_close_exe_image (void)
1845 mono_image_close (exe_image);
1849 * mono_get_root_domain:
1851 * The root AppDomain is the initial domain created by the runtime when it is
1852 * initialized. Programs execute on this AppDomain, but can create new ones
1853 * later. Currently there is no unmanaged API to create new AppDomains, this
1854 * must be done from managed code.
1856 * Returns: the root appdomain, to obtain the current domain, use mono_domain_get ()
1859 mono_get_root_domain (void)
1861 return mono_root_domain;
1867 * Returns: the current domain, to obtain the root domain use
1868 * mono_get_root_domain().
1873 return GET_APPDOMAIN ();
1877 mono_domain_unset (void)
1879 SET_APPDOMAIN (NULL);
1883 mono_domain_set_internal_with_options (MonoDomain *domain, gboolean migrate_exception)
1885 MonoInternalThread *thread;
1887 if (mono_domain_get () == domain)
1890 SET_APPDOMAIN (domain);
1891 SET_APPCONTEXT (domain->default_context);
1893 if (migrate_exception) {
1894 thread = mono_thread_internal_current ();
1895 if (!thread->abort_exc)
1898 g_assert (thread->abort_exc->object.vtable->domain != domain);
1899 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
1900 g_assert (thread->abort_exc->object.vtable->domain == domain);
1905 * mono_domain_set_internal:
1906 * @domain: the new domain
1908 * Sets the current domain to @domain.
1911 mono_domain_set_internal (MonoDomain *domain)
1913 mono_domain_set_internal_with_options (domain, TRUE);
1917 mono_domain_foreach (MonoDomainFunc func, gpointer user_data)
1923 * Create a copy of the data to avoid calling the user callback
1924 * inside the lock because that could lead to deadlocks.
1925 * We can do this because this function is not perf. critical.
1927 mono_appdomains_lock ();
1928 size = appdomain_list_size;
1929 copy = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1930 memcpy (copy, appdomains_list, appdomain_list_size * sizeof (void*));
1931 mono_appdomains_unlock ();
1933 for (i = 0; i < size; ++i) {
1935 func (copy [i], user_data);
1938 mono_gc_free_fixed (copy);
1942 * mono_domain_assembly_open:
1943 * @domain: the application domain
1944 * @name: file name of the assembly
1946 * fixme: maybe we should integrate this with mono_assembly_open ??
1949 mono_domain_assembly_open (MonoDomain *domain, const char *name)
1951 MonoDomain *current;
1955 mono_domain_assemblies_lock (domain);
1956 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1958 if (strcmp (name, ass->aname.name) == 0) {
1959 mono_domain_assemblies_unlock (domain);
1963 mono_domain_assemblies_unlock (domain);
1965 if (domain != mono_domain_get ()) {
1966 current = mono_domain_get ();
1968 mono_domain_set (domain, FALSE);
1969 ass = mono_assembly_open (name, NULL);
1970 mono_domain_set (current, FALSE);
1972 ass = mono_assembly_open (name, NULL);
1979 unregister_vtable_reflection_type (MonoVTable *vtable)
1981 MonoObject *type = vtable->type;
1983 if (type->vtable->klass != mono_defaults.monotype_class)
1984 MONO_GC_UNREGISTER_ROOT_IF_MOVING (vtable->type);
1988 mono_domain_free (MonoDomain *domain, gboolean force)
1990 int code_size, code_alloc;
1994 if ((domain == mono_root_domain) && !force) {
1995 g_warning ("cant unload root domain");
1999 if (mono_dont_free_domains)
2002 mono_profiler_appdomain_event (domain, MONO_PROFILE_START_UNLOAD);
2004 mono_debug_domain_unload (domain);
2006 mono_appdomains_lock ();
2007 appdomains_list [domain->domain_id] = NULL;
2008 mono_appdomains_unlock ();
2010 /* must do this early as it accesses fields and types */
2011 if (domain->special_static_fields) {
2012 mono_alloc_special_static_data_free (domain->special_static_fields);
2013 g_hash_table_destroy (domain->special_static_fields);
2014 domain->special_static_fields = NULL;
2018 * We must destroy all these hash tables here because they
2019 * contain references to managed objects belonging to the
2020 * domain. Once we let the GC clear the domain there must be
2021 * no more such references, or we'll crash if a collection
2024 mono_g_hash_table_destroy (domain->ldstr_table);
2025 domain->ldstr_table = NULL;
2027 mono_g_hash_table_destroy (domain->env);
2030 if (domain->tlsrec_list) {
2031 mono_thread_destroy_domain_tls (domain);
2032 domain->tlsrec_list = NULL;
2035 mono_reflection_cleanup_domain (domain);
2037 /* This must be done before type_hash is freed */
2038 if (domain->class_vtable_array) {
2040 for (i = 0; i < domain->class_vtable_array->len; ++i)
2041 unregister_vtable_reflection_type (g_ptr_array_index (domain->class_vtable_array, i));
2044 if (domain->type_hash) {
2045 mono_g_hash_table_destroy (domain->type_hash);
2046 domain->type_hash = NULL;
2048 if (domain->type_init_exception_hash) {
2049 mono_g_hash_table_destroy (domain->type_init_exception_hash);
2050 domain->type_init_exception_hash = NULL;
2053 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2054 MonoAssembly *ass = tmp->data;
2055 mono_assembly_release_gc_roots (ass);
2058 /* Have to zero out reference fields since they will be invalidated by the clear_domain () call below */
2059 for (p = (gpointer*)&domain->MONO_DOMAIN_FIRST_OBJECT; p < (gpointer*)&domain->MONO_DOMAIN_FIRST_GC_TRACKED; ++p)
2062 /* This needs to be done before closing assemblies */
2063 mono_gc_clear_domain (domain);
2065 /* Close dynamic assemblies first, since they have no ref count */
2066 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2067 MonoAssembly *ass = tmp->data;
2068 if (!ass->image || !image_is_dynamic (ass->image))
2070 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);
2071 if (!mono_assembly_close_except_image_pools (ass))
2075 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2076 MonoAssembly *ass = tmp->data;
2079 if (!ass->image || image_is_dynamic (ass->image))
2081 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);
2082 if (!mono_assembly_close_except_image_pools (ass))
2086 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2087 MonoAssembly *ass = tmp->data;
2089 mono_assembly_close_finish (ass);
2091 g_slist_free (domain->domain_assemblies);
2092 domain->domain_assemblies = NULL;
2095 * Send this after the assemblies have been unloaded and the domain is still in a
2098 mono_profiler_appdomain_event (domain, MONO_PROFILE_END_UNLOAD);
2100 if (free_domain_hook)
2101 free_domain_hook (domain);
2103 /* FIXME: free delegate_hash_table when it's used */
2104 if (domain->search_path) {
2105 g_strfreev (domain->search_path);
2106 domain->search_path = NULL;
2108 domain->create_proxy_for_type_method = NULL;
2109 domain->private_invoke_method = NULL;
2110 domain->default_context = NULL;
2111 domain->out_of_memory_ex = NULL;
2112 domain->null_reference_ex = NULL;
2113 domain->stack_overflow_ex = NULL;
2114 domain->ephemeron_tombstone = NULL;
2115 domain->entry_assembly = NULL;
2117 g_free (domain->friendly_name);
2118 domain->friendly_name = NULL;
2119 g_ptr_array_free (domain->class_vtable_array, TRUE);
2120 domain->class_vtable_array = NULL;
2121 g_hash_table_destroy (domain->proxy_vtable_hash);
2122 domain->proxy_vtable_hash = NULL;
2123 if (domain->static_data_array) {
2124 mono_gc_free_fixed (domain->static_data_array);
2125 domain->static_data_array = NULL;
2127 mono_internal_hash_table_destroy (&domain->jit_code_hash);
2130 * There might still be jit info tables of this domain which
2131 * are not freed. Since the domain cannot be in use anymore,
2132 * this will free them.
2134 mono_thread_hazardous_try_free_all ();
2135 if (domain->aot_modules)
2136 jit_info_table_free (domain->aot_modules);
2137 g_assert (domain->num_jit_info_tables == 1);
2138 jit_info_table_free (domain->jit_info_table);
2139 domain->jit_info_table = NULL;
2140 g_assert (!domain->jit_info_free_queue);
2142 /* collect statistics */
2143 code_alloc = mono_code_manager_size (domain->code_mp, &code_size);
2144 total_domain_code_alloc += code_alloc;
2145 max_domain_code_alloc = MAX (max_domain_code_alloc, code_alloc);
2146 max_domain_code_size = MAX (max_domain_code_size, code_size);
2148 if (debug_domain_unload) {
2149 mono_mempool_invalidate (domain->mp);
2150 mono_code_manager_invalidate (domain->code_mp);
2152 #ifndef DISABLE_PERFCOUNTERS
2153 mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (domain->mp);
2155 mono_mempool_destroy (domain->mp);
2157 mono_code_manager_destroy (domain->code_mp);
2158 domain->code_mp = NULL;
2160 lock_free_mempool_free (domain->lock_free_mp);
2161 domain->lock_free_mp = NULL;
2163 g_hash_table_destroy (domain->finalizable_objects_hash);
2164 domain->finalizable_objects_hash = NULL;
2165 if (domain->method_rgctx_hash) {
2166 g_hash_table_destroy (domain->method_rgctx_hash);
2167 domain->method_rgctx_hash = NULL;
2169 if (domain->generic_virtual_cases) {
2170 g_hash_table_destroy (domain->generic_virtual_cases);
2171 domain->generic_virtual_cases = NULL;
2173 if (domain->generic_virtual_thunks) {
2174 g_hash_table_destroy (domain->generic_virtual_thunks);
2175 domain->generic_virtual_thunks = NULL;
2177 if (domain->ftnptrs_hash) {
2178 g_hash_table_destroy (domain->ftnptrs_hash);
2179 domain->ftnptrs_hash = NULL;
2182 mono_mutex_destroy (&domain->finalizable_objects_hash_lock);
2183 mono_mutex_destroy (&domain->assemblies_lock);
2184 mono_mutex_destroy (&domain->jit_code_hash_lock);
2185 mono_mutex_destroy (&domain->lock);
2186 domain->setup = NULL;
2188 mono_gc_deregister_root ((char*)&(domain->MONO_DOMAIN_FIRST_GC_TRACKED));
2190 /* FIXME: anything else required ? */
2192 mono_gc_free_fixed (domain);
2194 #ifndef DISABLE_PERFCOUNTERS
2195 mono_perfcounters->loader_appdomains--;
2198 if (domain == mono_root_domain)
2199 mono_root_domain = NULL;
2203 * mono_domain_get_id:
2206 * Returns: the a domain for a specific domain id.
2209 mono_domain_get_by_id (gint32 domainid)
2211 MonoDomain * domain;
2213 mono_appdomains_lock ();
2214 if (domainid < appdomain_list_size)
2215 domain = appdomains_list [domainid];
2218 mono_appdomains_unlock ();
2224 mono_domain_get_id (MonoDomain *domain)
2226 return domain->domain_id;
2230 * mono_domain_alloc:
2232 * LOCKING: Acquires the domain lock.
2235 mono_domain_alloc (MonoDomain *domain, guint size)
2239 mono_domain_lock (domain);
2240 #ifndef DISABLE_PERFCOUNTERS
2241 mono_perfcounters->loader_bytes += size;
2243 res = mono_mempool_alloc (domain->mp, size);
2244 mono_domain_unlock (domain);
2250 * mono_domain_alloc0:
2252 * LOCKING: Acquires the domain lock.
2255 mono_domain_alloc0 (MonoDomain *domain, guint size)
2259 mono_domain_lock (domain);
2260 #ifndef DISABLE_PERFCOUNTERS
2261 mono_perfcounters->loader_bytes += size;
2263 res = mono_mempool_alloc0 (domain->mp, size);
2264 mono_domain_unlock (domain);
2270 mono_domain_alloc0_lock_free (MonoDomain *domain, guint size)
2272 return lock_free_mempool_alloc0 (domain->lock_free_mp, size);
2276 * mono_domain_code_reserve:
2278 * LOCKING: Acquires the domain lock.
2281 mono_domain_code_reserve (MonoDomain *domain, int size)
2285 mono_domain_lock (domain);
2286 res = mono_code_manager_reserve (domain->code_mp, size);
2287 mono_domain_unlock (domain);
2293 * mono_domain_code_reserve_align:
2295 * LOCKING: Acquires the domain lock.
2298 mono_domain_code_reserve_align (MonoDomain *domain, int size, int alignment)
2302 mono_domain_lock (domain);
2303 res = mono_code_manager_reserve_align (domain->code_mp, size, alignment);
2304 mono_domain_unlock (domain);
2310 * mono_domain_code_commit:
2312 * LOCKING: Acquires the domain lock.
2315 mono_domain_code_commit (MonoDomain *domain, void *data, int size, int newsize)
2317 mono_domain_lock (domain);
2318 mono_code_manager_commit (domain->code_mp, data, size, newsize);
2319 mono_domain_unlock (domain);
2322 #if defined(__native_client_codegen__) && defined(__native_client__)
2324 * Given the temporary buffer (allocated by mono_domain_code_reserve) into which
2325 * we are generating code, return a pointer to the destination in the dynamic
2326 * code segment into which the code will be copied when mono_domain_code_commit
2328 * LOCKING: Acquires the domain lock.
2331 nacl_domain_get_code_dest (MonoDomain *domain, void *data)
2334 mono_domain_lock (domain);
2335 dest = nacl_code_manager_get_code_dest (domain->code_mp, data);
2336 mono_domain_unlock (domain);
2341 * Convenience function which calls mono_domain_code_commit to validate and copy
2342 * the code. The caller sets *buf_base and *buf_size to the start and size of
2343 * the buffer (allocated by mono_domain_code_reserve), and *code_end to the byte
2344 * after the last instruction byte. On return, *buf_base will point to the start
2345 * of the copied in the code segment, and *code_end will point after the end of
2349 nacl_domain_code_validate (MonoDomain *domain, guint8 **buf_base, int buf_size, guint8 **code_end)
2351 guint8 *tmp = nacl_domain_get_code_dest (domain, *buf_base);
2352 mono_domain_code_commit (domain, *buf_base, buf_size, *code_end - *buf_base);
2353 *code_end = tmp + (*code_end - *buf_base);
2359 /* no-op versions of Native Client functions */
2362 nacl_domain_get_code_dest (MonoDomain *domain, void *data)
2368 nacl_domain_code_validate (MonoDomain *domain, guint8 **buf_base, int buf_size, guint8 **code_end)
2375 * mono_domain_code_foreach:
2376 * Iterate over the code thunks of the code manager of @domain.
2378 * The @func callback MUST not take any locks. If it really needs to, it must respect
2379 * the locking rules of the runtime: http://www.mono-project.com/Mono:Runtime:Documentation:ThreadSafety
2380 * LOCKING: Acquires the domain lock.
2384 mono_domain_code_foreach (MonoDomain *domain, MonoCodeManagerFunc func, void *user_data)
2386 mono_domain_lock (domain);
2387 mono_code_manager_foreach (domain->code_mp, func, user_data);
2388 mono_domain_unlock (domain);
2393 mono_context_set (MonoAppContext * new_context)
2395 SET_APPCONTEXT (new_context);
2399 mono_context_get (void)
2401 return GET_APPCONTEXT ();
2404 /* LOCKING: the caller holds the lock for this domain */
2406 mono_domain_add_class_static_data (MonoDomain *domain, MonoClass *klass, gpointer data, guint32 *bitmap)
2408 /* The first entry in the array is the index of the next free slot
2409 * and the total size of the array
2412 if (domain->static_data_array) {
2413 int size = GPOINTER_TO_INT (domain->static_data_array [1]);
2414 next = GPOINTER_TO_INT (domain->static_data_array [0]);
2416 /* 'data' is allocated by alloc_fixed */
2417 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * (size * 2), MONO_GC_ROOT_DESCR_FOR_FIXED (size * 2));
2418 mono_gc_memmove_aligned (new_array, domain->static_data_array, sizeof (gpointer) * size);
2420 new_array [1] = GINT_TO_POINTER (size);
2421 mono_gc_free_fixed (domain->static_data_array);
2422 domain->static_data_array = new_array;
2426 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * size, MONO_GC_ROOT_DESCR_FOR_FIXED (size));
2428 new_array [0] = GINT_TO_POINTER (next);
2429 new_array [1] = GINT_TO_POINTER (size);
2430 domain->static_data_array = new_array;
2432 domain->static_data_array [next++] = data;
2433 domain->static_data_array [0] = GINT_TO_POINTER (next);
2437 mono_get_corlib (void)
2439 return mono_defaults.corlib;
2443 mono_get_object_class (void)
2445 return mono_defaults.object_class;
2449 mono_get_byte_class (void)
2451 return mono_defaults.byte_class;
2455 mono_get_void_class (void)
2457 return mono_defaults.void_class;
2461 mono_get_boolean_class (void)
2463 return mono_defaults.boolean_class;
2467 mono_get_sbyte_class (void)
2469 return mono_defaults.sbyte_class;
2473 mono_get_int16_class (void)
2475 return mono_defaults.int16_class;
2479 mono_get_uint16_class (void)
2481 return mono_defaults.uint16_class;
2485 mono_get_int32_class (void)
2487 return mono_defaults.int32_class;
2491 mono_get_uint32_class (void)
2493 return mono_defaults.uint32_class;
2497 mono_get_intptr_class (void)
2499 return mono_defaults.int_class;
2503 mono_get_uintptr_class (void)
2505 return mono_defaults.uint_class;
2509 mono_get_int64_class (void)
2511 return mono_defaults.int64_class;
2515 mono_get_uint64_class (void)
2517 return mono_defaults.uint64_class;
2521 mono_get_single_class (void)
2523 return mono_defaults.single_class;
2527 mono_get_double_class (void)
2529 return mono_defaults.double_class;
2533 mono_get_char_class (void)
2535 return mono_defaults.char_class;
2539 mono_get_string_class (void)
2541 return mono_defaults.string_class;
2545 mono_get_enum_class (void)
2547 return mono_defaults.enum_class;
2551 mono_get_array_class (void)
2553 return mono_defaults.array_class;
2557 mono_get_thread_class (void)
2559 return mono_defaults.thread_class;
2563 mono_get_exception_class (void)
2565 return mono_defaults.exception_class;
2569 static char* get_attribute_value (const gchar **attribute_names,
2570 const gchar **attribute_values,
2571 const char *att_name)
2574 for (n=0; attribute_names[n] != NULL; n++) {
2575 if (strcmp (attribute_names[n], att_name) == 0)
2576 return g_strdup (attribute_values[n]);
2581 static void start_element (GMarkupParseContext *context,
2582 const gchar *element_name,
2583 const gchar **attribute_names,
2584 const gchar **attribute_values,
2588 AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2590 if (strcmp (element_name, "configuration") == 0) {
2591 app_config->configuration_count++;
2594 if (strcmp (element_name, "startup") == 0) {
2595 app_config->startup_count++;
2599 if (app_config->configuration_count != 1 || app_config->startup_count != 1)
2602 if (strcmp (element_name, "requiredRuntime") == 0) {
2603 app_config->required_runtime = get_attribute_value (attribute_names, attribute_values, "version");
2604 } else if (strcmp (element_name, "supportedRuntime") == 0) {
2605 char *version = get_attribute_value (attribute_names, attribute_values, "version");
2606 app_config->supported_runtimes = g_slist_append (app_config->supported_runtimes, version);
2610 static void end_element (GMarkupParseContext *context,
2611 const gchar *element_name,
2615 AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2617 if (strcmp (element_name, "configuration") == 0) {
2618 app_config->configuration_count--;
2619 } else if (strcmp (element_name, "startup") == 0) {
2620 app_config->startup_count--;
2624 static const GMarkupParser
2633 static AppConfigInfo *
2634 app_config_parse (const char *exe_filename)
2636 AppConfigInfo *app_config;
2637 GMarkupParseContext *context;
2640 const char *bundled_config;
2641 char *config_filename;
2643 bundled_config = mono_config_string_for_assembly_file (exe_filename);
2645 if (bundled_config) {
2646 text = g_strdup (bundled_config);
2647 len = strlen (text);
2649 config_filename = g_strconcat (exe_filename, ".config", NULL);
2651 if (!g_file_get_contents (config_filename, &text, &len, NULL)) {
2652 g_free (config_filename);
2655 g_free (config_filename);
2658 app_config = g_new0 (AppConfigInfo, 1);
2660 context = g_markup_parse_context_new (&mono_parser, 0, app_config, NULL);
2661 if (g_markup_parse_context_parse (context, text, len, NULL)) {
2662 g_markup_parse_context_end_parse (context, NULL);
2664 g_markup_parse_context_free (context);
2670 app_config_free (AppConfigInfo* app_config)
2673 GSList *list = app_config->supported_runtimes;
2674 while (list != NULL) {
2675 rt = (char*)list->data;
2677 list = g_slist_next (list);
2679 g_slist_free (app_config->supported_runtimes);
2680 g_free (app_config->required_runtime);
2681 g_free (app_config);
2685 static const MonoRuntimeInfo*
2686 get_runtime_by_version (const char *version)
2689 int max = G_N_ELEMENTS (supported_runtimes);
2695 for (n=0; n<max; n++) {
2696 if (strcmp (version, supported_runtimes[n].runtime_version) == 0)
2697 return &supported_runtimes[n];
2700 vlen = strlen (version);
2701 if (vlen >= 4 && version [1] - '0' >= 4) {
2702 for (n=0; n<max; n++) {
2703 if (strncmp (version, supported_runtimes[n].runtime_version, 4) == 0)
2704 return &supported_runtimes[n];
2712 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes)
2714 AppConfigInfo* app_config;
2716 const MonoRuntimeInfo* runtime = NULL;
2717 MonoImage *image = NULL;
2719 app_config = app_config_parse (exe_file);
2721 if (app_config != NULL) {
2722 /* Check supportedRuntime elements, if none is supported, fail.
2723 * If there are no such elements, look for a requiredRuntime element.
2725 if (app_config->supported_runtimes != NULL) {
2727 GSList *list = app_config->supported_runtimes;
2728 while (list != NULL) {
2729 version = (char*) list->data;
2730 runtime = get_runtime_by_version (version);
2731 if (runtime != NULL)
2732 runtimes [n++] = runtime;
2733 list = g_slist_next (list);
2735 runtimes [n] = NULL;
2736 app_config_free (app_config);
2740 /* Check the requiredRuntime element. This is for 1.0 apps only. */
2741 if (app_config->required_runtime != NULL) {
2742 runtimes [0] = get_runtime_by_version (app_config->required_runtime);
2743 runtimes [1] = NULL;
2744 app_config_free (app_config);
2747 app_config_free (app_config);
2750 /* Look for a runtime with the exact version */
2751 image = mono_assembly_open_from_bundle (exe_file, NULL, FALSE);
2754 image = mono_image_open (exe_file, NULL);
2756 if (image == NULL) {
2757 /* The image is wrong or the file was not found. In this case return
2758 * a default runtime and leave to the initialization method the work of
2759 * reporting the error.
2761 runtimes [0] = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
2762 runtimes [1] = NULL;
2768 runtimes [0] = get_runtime_by_version (image->version);
2769 runtimes [1] = NULL;
2774 * mono_get_runtime_info:
2776 * Returns: the version of the current runtime instance.
2778 const MonoRuntimeInfo*
2779 mono_get_runtime_info (void)
2781 return current_runtime;
2785 mono_debugger_check_runtime_version (const char *filename)
2787 const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
2788 const MonoRuntimeInfo *rinfo;
2791 get_runtimes_from_exe (filename, &image, runtimes);
2792 rinfo = runtimes [0];
2795 return g_strdup_printf ("Cannot get runtime version from assembly `%s'", filename);
2797 if (rinfo != current_runtime)
2798 return g_strdup_printf ("The Mono Debugger is currently using the `%s' runtime, but "
2799 "the assembly `%s' requires version `%s'", current_runtime->runtime_version,
2800 filename, rinfo->runtime_version);
2806 * mono_framework_version:
2808 * Return the major version of the framework curently executing.
2811 mono_framework_version (void)
2813 return current_runtime->framework_version [0] - '0';
2817 mono_enable_debug_domain_unload (gboolean enable)
2819 debug_domain_unload = enable;
2822 MonoAotCacheConfig *
2823 mono_get_aot_cache_config (void)
2825 return &aot_cache_config;