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() EnterCriticalSection (&appdomains_mutex)
97 #define mono_appdomains_unlock() LeaveCriticalSection (&appdomains_mutex)
98 static CRITICAL_SECTION 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 /* This is intentionally not in the header file, so people don't misuse it. */
142 extern void _mono_debug_init_corlib (MonoDomain *domain);
145 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes);
147 static const MonoRuntimeInfo*
148 get_runtime_by_version (const char *version);
151 mono_domain_get_tls_key (void)
153 return appdomain_thread_id;
157 mono_domain_get_tls_offset (void)
160 MONO_THREAD_VAR_OFFSET (tls_appdomain, offset);
161 /* __asm ("jmp 1f; .section writetext, \"awx\"; 1: movl $tls_appdomain@ntpoff, %0; jmp 2f; .previous; 2:"
166 #define JIT_INFO_TABLE_FILL_RATIO_NOM 3
167 #define JIT_INFO_TABLE_FILL_RATIO_DENOM 4
168 #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)
170 #define JIT_INFO_TABLE_LOW_WATERMARK(n) ((n) / 2)
171 #define JIT_INFO_TABLE_HIGH_WATERMARK(n) ((n) * 5 / 6)
173 #define JIT_INFO_TOMBSTONE_MARKER ((MonoMethod*)NULL)
174 #define IS_JIT_INFO_TOMBSTONE(ji) ((ji)->d.method == JIT_INFO_TOMBSTONE_MARKER)
176 #define JIT_INFO_TABLE_HAZARD_INDEX 0
177 #define JIT_INFO_HAZARD_INDEX 1
180 jit_info_table_num_elements (MonoJitInfoTable *table)
183 int num_elements = 0;
185 for (i = 0; i < table->num_chunks; ++i) {
186 MonoJitInfoTableChunk *chunk = table->chunks [i];
187 int chunk_num_elements = chunk->num_elements;
190 for (j = 0; j < chunk_num_elements; ++j) {
191 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j]))
199 static MonoJitInfoTableChunk*
200 jit_info_table_new_chunk (void)
202 MonoJitInfoTableChunk *chunk = g_new0 (MonoJitInfoTableChunk, 1);
208 static MonoJitInfoTable *
209 jit_info_table_new (MonoDomain *domain)
211 MonoJitInfoTable *table = g_malloc0 (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*));
213 table->domain = domain;
214 table->num_chunks = 1;
215 table->chunks [0] = jit_info_table_new_chunk ();
221 jit_info_table_free (MonoJitInfoTable *table)
224 int num_chunks = table->num_chunks;
225 MonoDomain *domain = table->domain;
227 mono_domain_lock (domain);
229 table->domain->num_jit_info_tables--;
230 if (table->domain->num_jit_info_tables <= 1) {
233 for (list = table->domain->jit_info_free_queue; list; list = list->next)
236 g_slist_free (table->domain->jit_info_free_queue);
237 table->domain->jit_info_free_queue = NULL;
240 /* At this point we assume that there are no other threads
241 still accessing the table, so we don't have to worry about
242 hazardous pointers. */
244 for (i = 0; i < num_chunks; ++i) {
245 MonoJitInfoTableChunk *chunk = table->chunks [i];
249 if (--chunk->refcount > 0)
252 num_elements = chunk->num_elements;
253 for (j = 0; j < num_elements; ++j) {
254 MonoJitInfo *ji = chunk->data [j];
256 if (IS_JIT_INFO_TOMBSTONE (ji))
263 mono_domain_unlock (domain);
268 /* The jit_info_table is sorted in ascending order by the end
269 * addresses of the compiled methods. The reason why we have to do
270 * this is that once we introduce tombstones, it becomes possible for
271 * code ranges to overlap, and if we sort by code start and insert at
272 * the back of the table, we cannot guarantee that we won't overlook
275 * There are actually two possible ways to do the sorting and
276 * inserting which work with our lock-free mechanism:
278 * 1. Sort by start address and insert at the front. When looking for
279 * an entry, find the last one with a start address lower than the one
280 * you're looking for, then work your way to the front of the table.
282 * 2. Sort by end address and insert at the back. When looking for an
283 * entry, find the first one with an end address higher than the one
284 * you're looking for, then work your way to the end of the table.
286 * We chose the latter out of convenience.
289 jit_info_table_index (MonoJitInfoTable *table, gint8 *addr)
291 int left = 0, right = table->num_chunks;
293 g_assert (left < right);
296 int pos = (left + right) / 2;
297 MonoJitInfoTableChunk *chunk = table->chunks [pos];
299 if (addr < chunk->last_code_end)
303 } while (left < right);
304 g_assert (left == right);
306 if (left >= table->num_chunks)
307 return table->num_chunks - 1;
312 jit_info_table_chunk_index (MonoJitInfoTableChunk *chunk, MonoThreadHazardPointers *hp, gint8 *addr)
314 int left = 0, right = chunk->num_elements;
316 while (left < right) {
317 int pos = (left + right) / 2;
318 MonoJitInfo *ji = get_hazardous_pointer((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
319 gint8 *code_end = (gint8*)ji->code_start + ji->code_size;
326 g_assert (left == right);
332 jit_info_table_find (MonoJitInfoTable *table, MonoThreadHazardPointers *hp, gint8 *addr)
337 chunk_pos = jit_info_table_index (table, (gint8*)addr);
338 g_assert (chunk_pos < table->num_chunks);
340 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], hp, (gint8*)addr);
342 /* We now have a position that's very close to that of the
343 first element whose end address is higher than the one
344 we're looking for. If we don't have the exact position,
345 then we have a position below that one, so we'll just
346 search upward until we find our element. */
348 MonoJitInfoTableChunk *chunk = table->chunks [chunk_pos];
350 while (pos < chunk->num_elements) {
351 ji = get_hazardous_pointer ((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
355 if (IS_JIT_INFO_TOMBSTONE (ji)) {
356 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
359 if ((gint8*)addr >= (gint8*)ji->code_start
360 && (gint8*)addr < (gint8*)ji->code_start + ji->code_size) {
361 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
365 /* If we find a non-tombstone element which is already
366 beyond what we're looking for, we have to end the
368 if ((gint8*)addr < (gint8*)ji->code_start)
374 } while (chunk_pos < table->num_chunks);
378 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
383 * mono_jit_info_table_find_internal:
385 * If TRY_AOT is FALSE, avoid loading information for missing methods from AOT images, which is currently not async safe.
386 * In this case, only those AOT methods will be found whose jit info is already loaded.
387 * ASYNC SAFETY: When called in an async context (mono_thread_info_is_async_context ()), this is async safe.
388 * In this case, the returned MonoJitInfo might not have metadata information, in particular,
389 * mono_jit_info_get_method () could fail.
392 mono_jit_info_table_find_internal (MonoDomain *domain, char *addr, gboolean try_aot)
394 MonoJitInfoTable *table;
395 MonoJitInfo *ji, *module_ji;
396 MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
398 ++mono_stats.jit_info_table_lookup_count;
400 /* First we have to get the domain's jit_info_table. This is
401 complicated by the fact that a writer might substitute a
402 new table and free the old one. What the writer guarantees
403 us is that it looks at the hazard pointers after it has
404 changed the jit_info_table pointer. So, if we guard the
405 table by a hazard pointer and make sure that the pointer is
406 still there after we've made it hazardous, we don't have to
407 worry about the writer freeing the table. */
408 table = get_hazardous_pointer ((gpointer volatile*)&domain->jit_info_table, hp, JIT_INFO_TABLE_HAZARD_INDEX);
410 ji = jit_info_table_find (table, hp, (gint8*)addr);
412 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
416 /* Maybe its an AOT module */
417 if (try_aot && mono_root_domain && mono_root_domain->aot_modules) {
418 table = get_hazardous_pointer ((gpointer volatile*)&mono_root_domain->aot_modules, hp, JIT_INFO_TABLE_HAZARD_INDEX);
419 module_ji = jit_info_table_find (table, hp, (gint8*)addr);
421 ji = jit_info_find_in_aot_func (domain, module_ji->d.image, addr);
423 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
430 mono_jit_info_table_find (MonoDomain *domain, char *addr)
432 return mono_jit_info_table_find_internal (domain, addr, TRUE);
435 static G_GNUC_UNUSED void
436 jit_info_table_check (MonoJitInfoTable *table)
440 for (i = 0; i < table->num_chunks; ++i) {
441 MonoJitInfoTableChunk *chunk = table->chunks [i];
444 g_assert (chunk->refcount > 0 /* && chunk->refcount <= 8 */);
445 if (chunk->refcount > 10)
446 printf("warning: chunk refcount is %d\n", chunk->refcount);
447 g_assert (chunk->num_elements <= MONO_JIT_INFO_TABLE_CHUNK_SIZE);
449 for (j = 0; j < chunk->num_elements; ++j) {
450 MonoJitInfo *this = chunk->data [j];
453 g_assert ((gint8*)this->code_start + this->code_size <= chunk->last_code_end);
455 if (j < chunk->num_elements - 1)
456 next = chunk->data [j + 1];
457 else if (i < table->num_chunks - 1) {
460 for (k = i + 1; k < table->num_chunks; ++k)
461 if (table->chunks [k]->num_elements > 0)
464 if (k >= table->num_chunks)
467 g_assert (table->chunks [k]->num_elements > 0);
468 next = table->chunks [k]->data [0];
472 g_assert ((gint8*)this->code_start + this->code_size <= (gint8*)next->code_start + next->code_size);
477 static MonoJitInfoTable*
478 jit_info_table_realloc (MonoJitInfoTable *old)
481 int num_elements = jit_info_table_num_elements (old);
484 int new_chunk, new_element;
485 MonoJitInfoTable *new;
487 /* number of needed places for elements needed */
488 required_size = (int)((long)num_elements * JIT_INFO_TABLE_FILL_RATIO_DENOM / JIT_INFO_TABLE_FILL_RATIO_NOM);
489 num_chunks = (required_size + MONO_JIT_INFO_TABLE_CHUNK_SIZE - 1) / MONO_JIT_INFO_TABLE_CHUNK_SIZE;
490 if (num_chunks == 0) {
491 g_assert (num_elements == 0);
492 return jit_info_table_new (old->domain);
494 g_assert (num_chunks > 0);
496 new = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*) * num_chunks);
497 new->domain = old->domain;
498 new->num_chunks = num_chunks;
500 for (i = 0; i < num_chunks; ++i)
501 new->chunks [i] = jit_info_table_new_chunk ();
505 for (i = 0; i < old->num_chunks; ++i) {
506 MonoJitInfoTableChunk *chunk = old->chunks [i];
507 int chunk_num_elements = chunk->num_elements;
510 for (j = 0; j < chunk_num_elements; ++j) {
511 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j])) {
512 g_assert (new_chunk < num_chunks);
513 new->chunks [new_chunk]->data [new_element] = chunk->data [j];
514 if (++new_element >= JIT_INFO_TABLE_FILLED_NUM_ELEMENTS) {
515 new->chunks [new_chunk]->num_elements = new_element;
523 if (new_chunk < num_chunks) {
524 g_assert (new_chunk == num_chunks - 1);
525 new->chunks [new_chunk]->num_elements = new_element;
526 g_assert (new->chunks [new_chunk]->num_elements > 0);
529 for (i = 0; i < num_chunks; ++i) {
530 MonoJitInfoTableChunk *chunk = new->chunks [i];
531 MonoJitInfo *ji = chunk->data [chunk->num_elements - 1];
533 new->chunks [i]->last_code_end = (gint8*)ji->code_start + ji->code_size;
540 jit_info_table_split_chunk (MonoJitInfoTableChunk *chunk, MonoJitInfoTableChunk **new1p, MonoJitInfoTableChunk **new2p)
542 MonoJitInfoTableChunk *new1 = jit_info_table_new_chunk ();
543 MonoJitInfoTableChunk *new2 = jit_info_table_new_chunk ();
545 g_assert (chunk->num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE);
547 new1->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE / 2;
548 new2->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE - new1->num_elements;
550 memcpy ((void*)new1->data, (void*)chunk->data, sizeof (MonoJitInfo*) * new1->num_elements);
551 memcpy ((void*)new2->data, (void*)(chunk->data + new1->num_elements), sizeof (MonoJitInfo*) * new2->num_elements);
553 new1->last_code_end = (gint8*)new1->data [new1->num_elements - 1]->code_start
554 + new1->data [new1->num_elements - 1]->code_size;
555 new2->last_code_end = (gint8*)new2->data [new2->num_elements - 1]->code_start
556 + new2->data [new2->num_elements - 1]->code_size;
562 static MonoJitInfoTable*
563 jit_info_table_copy_and_split_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
565 MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
566 + sizeof (MonoJitInfoTableChunk*) * (table->num_chunks + 1));
569 new_table->domain = table->domain;
570 new_table->num_chunks = table->num_chunks + 1;
573 for (i = 0; i < table->num_chunks; ++i) {
574 if (table->chunks [i] == chunk) {
575 jit_info_table_split_chunk (chunk, &new_table->chunks [j], &new_table->chunks [j + 1]);
578 new_table->chunks [j] = table->chunks [i];
579 ++new_table->chunks [j]->refcount;
584 g_assert (j == new_table->num_chunks);
589 static MonoJitInfoTableChunk*
590 jit_info_table_purify_chunk (MonoJitInfoTableChunk *old)
592 MonoJitInfoTableChunk *new = jit_info_table_new_chunk ();
596 for (i = 0; i < old->num_elements; ++i) {
597 if (!IS_JIT_INFO_TOMBSTONE (old->data [i]))
598 new->data [j++] = old->data [i];
601 new->num_elements = j;
602 if (new->num_elements > 0)
603 new->last_code_end = (gint8*)new->data [j - 1]->code_start + new->data [j - 1]->code_size;
605 new->last_code_end = old->last_code_end;
610 static MonoJitInfoTable*
611 jit_info_table_copy_and_purify_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
613 MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
614 + sizeof (MonoJitInfoTableChunk*) * table->num_chunks);
617 new_table->domain = table->domain;
618 new_table->num_chunks = table->num_chunks;
621 for (i = 0; i < table->num_chunks; ++i) {
622 if (table->chunks [i] == chunk)
623 new_table->chunks [j++] = jit_info_table_purify_chunk (table->chunks [i]);
625 new_table->chunks [j] = table->chunks [i];
626 ++new_table->chunks [j]->refcount;
631 g_assert (j == new_table->num_chunks);
636 /* As we add an element to the table the case can arise that the chunk
637 * to which we need to add is already full. In that case we have to
638 * allocate a new table and do something about that chunk. We have
639 * several strategies:
641 * If the number of elements in the table is below the low watermark
642 * or above the high watermark, we reallocate the whole table.
643 * Otherwise we only concern ourselves with the overflowing chunk:
645 * If there are no tombstones in the chunk then we split the chunk in
646 * two, each half full.
648 * If the chunk does contain tombstones, we just make a new copy of
649 * the chunk without the tombstones, which will have room for at least
650 * the one element we have to add.
652 static MonoJitInfoTable*
653 jit_info_table_chunk_overflow (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
655 int num_elements = jit_info_table_num_elements (table);
658 if (num_elements < JIT_INFO_TABLE_LOW_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)
659 || num_elements > JIT_INFO_TABLE_HIGH_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)) {
660 //printf ("reallocing table\n");
661 return jit_info_table_realloc (table);
664 /* count the number of non-tombstone elements in the chunk */
666 for (i = 0; i < chunk->num_elements; ++i) {
667 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [i]))
671 if (num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
672 //printf ("splitting chunk\n");
673 return jit_info_table_copy_and_split_chunk (table, chunk);
676 //printf ("purifying chunk\n");
677 return jit_info_table_copy_and_purify_chunk (table, chunk);
680 /* We add elements to the table by first making space for them by
681 * shifting the elements at the back to the right, one at a time.
682 * This results in duplicate entries during the process, but during
683 * all the time the table is in a sorted state. Also, when an element
684 * is replaced by another one, the element that replaces it has an end
685 * address that is equal to or lower than that of the replaced
686 * element. That property is necessary to guarantee that when
687 * searching for an element we end up at a position not higher than
688 * the one we're looking for (i.e. we either find the element directly
689 * or we end up to the left of it).
692 jit_info_table_add (MonoDomain *domain, MonoJitInfoTable *volatile *table_ptr, MonoJitInfo *ji)
694 MonoJitInfoTable *table;
695 MonoJitInfoTableChunk *chunk;
703 chunk_pos = jit_info_table_index (table, (gint8*)ji->code_start + ji->code_size);
704 g_assert (chunk_pos < table->num_chunks);
705 chunk = table->chunks [chunk_pos];
707 if (chunk->num_elements >= MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
708 MonoJitInfoTable *new_table = jit_info_table_chunk_overflow (table, chunk);
710 /* Debugging code, should be removed. */
711 //jit_info_table_check (new_table);
713 *table_ptr = new_table;
714 mono_memory_barrier ();
715 domain->num_jit_info_tables++;
716 mono_thread_hazardous_free_or_queue (table, (MonoHazardousFreeFunc)jit_info_table_free, TRUE, FALSE);
722 /* Debugging code, should be removed. */
723 //jit_info_table_check (table);
725 num_elements = chunk->num_elements;
727 pos = jit_info_table_chunk_index (chunk, NULL, (gint8*)ji->code_start + ji->code_size);
729 /* First we need to size up the chunk by one, by copying the
730 last item, or inserting the first one, if the table is
732 if (num_elements > 0)
733 chunk->data [num_elements] = chunk->data [num_elements - 1];
735 chunk->data [0] = ji;
736 mono_memory_write_barrier ();
737 chunk->num_elements = ++num_elements;
739 /* Shift the elements up one by one. */
740 for (i = num_elements - 2; i >= pos; --i) {
741 mono_memory_write_barrier ();
742 chunk->data [i + 1] = chunk->data [i];
745 /* Now we have room and can insert the new item. */
746 mono_memory_write_barrier ();
747 chunk->data [pos] = ji;
749 /* Set the high code end address chunk entry. */
750 chunk->last_code_end = (gint8*)chunk->data [chunk->num_elements - 1]->code_start
751 + chunk->data [chunk->num_elements - 1]->code_size;
753 /* Debugging code, should be removed. */
754 //jit_info_table_check (table);
758 mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
760 g_assert (ji->d.method != NULL);
762 mono_domain_lock (domain);
764 ++mono_stats.jit_info_table_insert_count;
766 jit_info_table_add (domain, &domain->jit_info_table, ji);
768 mono_domain_unlock (domain);
772 mono_jit_info_make_tombstone (MonoJitInfo *ji)
774 MonoJitInfo *tombstone = g_new0 (MonoJitInfo, 1);
776 tombstone->code_start = ji->code_start;
777 tombstone->code_size = ji->code_size;
778 tombstone->d.method = JIT_INFO_TOMBSTONE_MARKER;
784 * LOCKING: domain lock
787 mono_jit_info_free_or_queue (MonoDomain *domain, MonoJitInfo *ji)
789 if (domain->num_jit_info_tables <= 1) {
790 /* Can it actually happen that we only have one table
791 but ji is still hazardous? */
792 mono_thread_hazardous_free_or_queue (ji, g_free, TRUE, FALSE);
794 domain->jit_info_free_queue = g_slist_prepend (domain->jit_info_free_queue, ji);
799 jit_info_table_remove (MonoJitInfoTable *table, MonoJitInfo *ji)
801 MonoJitInfoTableChunk *chunk;
802 gpointer start = ji->code_start;
805 chunk_pos = jit_info_table_index (table, start);
806 g_assert (chunk_pos < table->num_chunks);
808 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], NULL, start);
811 chunk = table->chunks [chunk_pos];
813 while (pos < chunk->num_elements) {
814 if (chunk->data [pos] == ji)
817 g_assert (IS_JIT_INFO_TOMBSTONE (chunk->data [pos]));
818 g_assert ((guint8*)chunk->data [pos]->code_start + chunk->data [pos]->code_size
819 <= (guint8*)ji->code_start + ji->code_size);
826 } while (chunk_pos < table->num_chunks);
829 g_assert (chunk->data [pos] == ji);
831 chunk->data [pos] = mono_jit_info_make_tombstone (ji);
833 /* Debugging code, should be removed. */
834 //jit_info_table_check (table);
838 mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
840 MonoJitInfoTable *table;
842 mono_domain_lock (domain);
843 table = domain->jit_info_table;
845 ++mono_stats.jit_info_table_remove_count;
847 jit_info_table_remove (table, ji);
849 mono_jit_info_free_or_queue (domain, ji);
851 mono_domain_unlock (domain);
855 mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
859 g_assert (mono_root_domain);
860 mono_domain_lock (mono_root_domain);
863 * We reuse MonoJitInfoTable to store AOT module info,
864 * this gives us async-safe lookup.
866 if (!mono_root_domain->aot_modules) {
867 mono_root_domain->num_jit_info_tables ++;
868 mono_root_domain->aot_modules = jit_info_table_new (mono_root_domain);
871 ji = g_new0 (MonoJitInfo, 1);
873 ji->code_start = start;
874 ji->code_size = (guint8*)end - (guint8*)start;
875 jit_info_table_add (mono_root_domain, &mono_root_domain->aot_modules, ji);
877 mono_domain_unlock (mono_root_domain);
881 mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func)
883 jit_info_find_in_aot_func = func;
887 mono_jit_info_get_code_start (MonoJitInfo* ji)
889 return ji->code_start;
893 mono_jit_info_get_code_size (MonoJitInfo* ji)
895 return ji->code_size;
899 mono_jit_info_get_method (MonoJitInfo* ji)
901 g_assert (!ji->async);
906 jit_info_key_extract (gpointer value)
908 MonoJitInfo *info = (MonoJitInfo*)value;
910 return info->d.method;
914 jit_info_next_value (gpointer value)
916 MonoJitInfo *info = (MonoJitInfo*)value;
918 return (gpointer*)&info->next_jit_code_hash;
922 mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
924 mono_internal_hash_table_init (jit_code_hash,
925 mono_aligned_addr_hash,
926 jit_info_key_extract,
927 jit_info_next_value);
931 mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
933 if (ji->has_generic_jit_info)
934 return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
940 * mono_jit_info_get_generic_sharing_context:
943 * Returns the jit info's generic sharing context, or NULL if it
946 MonoGenericSharingContext*
947 mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
949 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
952 return gi->generic_sharing_context;
958 * mono_jit_info_set_generic_sharing_context:
960 * @gsctx: a generic sharing context
962 * Sets the jit info's generic sharing context. The jit info must
963 * have memory allocated for the context.
966 mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
968 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
972 gi->generic_sharing_context = gsctx;
975 MonoTryBlockHoleTableJitInfo*
976 mono_jit_info_get_try_block_hole_table_info (MonoJitInfo *ji)
978 if (ji->has_try_block_holes) {
979 char *ptr = (char*)&ji->clauses [ji->num_clauses];
980 if (ji->has_generic_jit_info)
981 ptr += sizeof (MonoGenericJitInfo);
982 return (MonoTryBlockHoleTableJitInfo*)ptr;
989 try_block_hole_table_size (MonoJitInfo *ji)
991 MonoTryBlockHoleTableJitInfo *table;
993 table = mono_jit_info_get_try_block_hole_table_info (ji);
995 return sizeof (MonoTryBlockHoleTableJitInfo) + table->num_holes * sizeof (MonoTryBlockHoleJitInfo);
999 mono_jit_info_get_arch_eh_info (MonoJitInfo *ji)
1001 if (ji->has_arch_eh_info) {
1002 char *ptr = (char*)&ji->clauses [ji->num_clauses];
1003 if (ji->has_generic_jit_info)
1004 ptr += sizeof (MonoGenericJitInfo);
1005 if (ji->has_try_block_holes)
1006 ptr += try_block_hole_table_size (ji);
1007 return (MonoArchEHJitInfo*)ptr;
1014 mono_jit_info_get_cas_info (MonoJitInfo *ji)
1016 if (ji->has_cas_info) {
1017 char *ptr = (char*)&ji->clauses [ji->num_clauses];
1018 if (ji->has_generic_jit_info)
1019 ptr += sizeof (MonoGenericJitInfo);
1020 if (ji->has_try_block_holes)
1021 ptr += try_block_hole_table_size (ji);
1022 if (ji->has_arch_eh_info)
1023 ptr += sizeof (MonoArchEHJitInfo);
1024 return (MonoMethodCasInfo*)ptr;
1030 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
1031 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
1033 static LockFreeMempool*
1034 lock_free_mempool_new (void)
1036 return g_new0 (LockFreeMempool, 1);
1040 lock_free_mempool_free (LockFreeMempool *mp)
1042 LockFreeMempoolChunk *chunk, *next;
1047 mono_vfree (chunk, mono_pagesize ());
1054 * This is async safe
1056 static LockFreeMempoolChunk*
1057 lock_free_mempool_chunk_new (LockFreeMempool *mp, int len)
1059 LockFreeMempoolChunk *chunk, *prev;
1062 size = mono_pagesize ();
1063 while (size - sizeof (LockFreeMempoolChunk) < len)
1064 size += mono_pagesize ();
1065 chunk = mono_valloc (0, size, MONO_MMAP_READ|MONO_MMAP_WRITE);
1067 chunk->mem = ALIGN_PTR_TO ((char*)chunk + sizeof (LockFreeMempoolChunk), 16);
1068 chunk->size = ((char*)chunk + size) - (char*)chunk->mem;
1071 /* Add to list of chunks lock-free */
1074 if (InterlockedCompareExchangePointer ((volatile gpointer*)&mp->chunks, chunk, prev) == prev)
1083 * This is async safe
1086 lock_free_mempool_alloc0 (LockFreeMempool *mp, guint size)
1088 LockFreeMempoolChunk *chunk;
1092 // FIXME: Free the allocator
1094 size = ALIGN_TO (size, 8);
1095 chunk = mp->current;
1097 chunk = lock_free_mempool_chunk_new (mp, size);
1098 mono_memory_barrier ();
1100 mp->current = chunk;
1103 /* The code below is lock-free, 'chunk' is shared state */
1104 oldpos = InterlockedExchangeAdd (&chunk->pos, size);
1105 if (oldpos + size > chunk->size) {
1106 chunk = lock_free_mempool_chunk_new (mp, size);
1107 g_assert (chunk->pos + size <= chunk->size);
1110 mono_memory_barrier ();
1111 mp->current = chunk;
1113 res = (char*)chunk->mem + oldpos;
1120 mono_install_create_domain_hook (MonoCreateDomainFunc func)
1122 create_domain_hook = func;
1126 mono_install_free_domain_hook (MonoFreeDomainFunc func)
1128 free_domain_hook = func;
1132 * mono_string_equal:
1133 * @s1: First string to compare
1134 * @s2: Second string to compare
1136 * Returns FALSE if the strings differ.
1139 mono_string_equal (MonoString *s1, MonoString *s2)
1141 int l1 = mono_string_length (s1);
1142 int l2 = mono_string_length (s2);
1149 return memcmp (mono_string_chars (s1), mono_string_chars (s2), l1 * 2) == 0;
1154 * @s: the string to hash
1156 * Returns the hash for the string.
1159 mono_string_hash (MonoString *s)
1161 const guint16 *p = mono_string_chars (s);
1162 int i, len = mono_string_length (s);
1165 for (i = 0; i < len; i++) {
1166 h = (h << 5) - h + *p;
1174 mono_ptrarray_equal (gpointer *s1, gpointer *s2)
1176 int len = GPOINTER_TO_INT (s1 [0]);
1177 if (len != GPOINTER_TO_INT (s2 [0]))
1180 return memcmp (s1 + 1, s2 + 1, len * sizeof(gpointer)) == 0;
1184 mono_ptrarray_hash (gpointer *s)
1187 int len = GPOINTER_TO_INT (s [0]);
1190 for (i = 1; i < len; i++)
1191 hash += GPOINTER_TO_UINT (s [i]);
1197 * Allocate an id for domain and set domain->domain_id.
1198 * LOCKING: must be called while holding appdomains_mutex.
1199 * We try to assign low numbers to the domain, so it can be used
1200 * as an index in data tables to lookup domain-specific info
1201 * with minimal memory overhead. We also try not to reuse the
1202 * same id too quickly (to help debugging).
1205 domain_id_alloc (MonoDomain *domain)
1208 if (!appdomains_list) {
1209 appdomain_list_size = 2;
1210 appdomains_list = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1212 for (i = appdomain_next; i < appdomain_list_size; ++i) {
1213 if (!appdomains_list [i]) {
1219 for (i = 0; i < appdomain_next; ++i) {
1220 if (!appdomains_list [i]) {
1227 MonoDomain **new_list;
1228 int new_size = appdomain_list_size * 2;
1229 if (new_size >= (1 << 16))
1230 g_assert_not_reached ();
1231 id = appdomain_list_size;
1232 new_list = mono_gc_alloc_fixed (new_size * sizeof (void*), NULL);
1233 memcpy (new_list, appdomains_list, appdomain_list_size * sizeof (void*));
1234 mono_gc_free_fixed (appdomains_list);
1235 appdomains_list = new_list;
1236 appdomain_list_size = new_size;
1238 domain->domain_id = id;
1239 appdomains_list [id] = domain;
1241 if (appdomain_next > appdomain_list_size)
1246 static gsize domain_gc_bitmap [sizeof(MonoDomain)/4/32 + 1];
1247 static gpointer domain_gc_desc = NULL;
1248 static guint32 domain_shadow_serial = 0L;
1251 mono_domain_create (void)
1254 guint32 shadow_serial;
1256 mono_appdomains_lock ();
1257 shadow_serial = domain_shadow_serial++;
1259 if (!domain_gc_desc) {
1260 unsigned int i, bit = 0;
1261 for (i = G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_OBJECT); i < G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_GC_TRACKED); i += sizeof (gpointer)) {
1262 bit = i / sizeof (gpointer);
1263 domain_gc_bitmap [bit / 32] |= (gsize) 1 << (bit % 32);
1265 domain_gc_desc = mono_gc_make_descr_from_bitmap ((gsize*)domain_gc_bitmap, bit + 1);
1267 mono_appdomains_unlock ();
1269 #ifdef HAVE_BOEHM_GC
1271 * Boehm doesn't like roots inside GC allocated objects, and alloc_fixed returns
1272 * a GC_MALLOC-ed object, contrary to the api docs. This causes random crashes when
1273 * running the corlib test suite.
1274 * To solve this, we pass a NULL descriptor, and don't register roots.
1276 domain = mono_gc_alloc_fixed (sizeof (MonoDomain), NULL);
1278 domain = mono_gc_alloc_fixed (sizeof (MonoDomain), domain_gc_desc);
1279 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);
1281 domain->shadow_serial = shadow_serial;
1282 domain->domain = NULL;
1283 domain->setup = NULL;
1284 domain->friendly_name = NULL;
1285 domain->search_path = NULL;
1287 mono_profiler_appdomain_event (domain, MONO_PROFILE_START_LOAD);
1289 domain->mp = mono_mempool_new ();
1290 domain->code_mp = mono_code_manager_new ();
1291 domain->lock_free_mp = lock_free_mempool_new ();
1292 domain->env = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1293 domain->domain_assemblies = NULL;
1294 domain->assembly_bindings = NULL;
1295 domain->assembly_bindings_parsed = FALSE;
1296 domain->class_vtable_array = g_ptr_array_new ();
1297 domain->proxy_vtable_hash = g_hash_table_new ((GHashFunc)mono_ptrarray_hash, (GCompareFunc)mono_ptrarray_equal);
1298 domain->static_data_array = NULL;
1299 mono_jit_code_hash_init (&domain->jit_code_hash);
1300 domain->ldstr_table = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1301 domain->num_jit_info_tables = 1;
1302 domain->jit_info_table = jit_info_table_new (domain);
1303 domain->jit_info_free_queue = NULL;
1304 domain->finalizable_objects_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1305 domain->ftnptrs_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1307 InitializeCriticalSection (&domain->lock);
1308 InitializeCriticalSection (&domain->assemblies_lock);
1309 InitializeCriticalSection (&domain->jit_code_hash_lock);
1310 InitializeCriticalSection (&domain->finalizable_objects_hash_lock);
1312 domain->method_rgctx_hash = NULL;
1314 mono_appdomains_lock ();
1315 domain_id_alloc (domain);
1316 mono_appdomains_unlock ();
1318 #ifndef DISABLE_PERFCOUNTERS
1319 mono_perfcounters->loader_appdomains++;
1320 mono_perfcounters->loader_total_appdomains++;
1323 mono_debug_domain_create (domain);
1325 if (create_domain_hook)
1326 create_domain_hook (domain);
1328 mono_profiler_appdomain_loaded (domain, MONO_PROFILE_OK);
1334 * mono_init_internal:
1336 * Creates the initial application domain and initializes the mono_defaults
1338 * This function is guaranteed to not run any IL code.
1339 * If exe_filename is not NULL, the method will determine the required runtime
1340 * from the exe configuration file or the version PE field.
1341 * If runtime_version is not NULL, that runtime version will be used.
1342 * Either exe_filename or runtime_version must be provided.
1344 * Returns: the initial domain.
1347 mono_init_internal (const char *filename, const char *exe_filename, const char *runtime_version)
1349 static MonoDomain *domain = NULL;
1350 MonoAssembly *ass = NULL;
1351 MonoImageOpenStatus status = MONO_IMAGE_OK;
1352 const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
1355 #ifdef DEBUG_DOMAIN_UNLOAD
1356 debug_domain_unload = TRUE;
1360 g_assert_not_reached ();
1363 /* Avoid system error message boxes. */
1364 SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1371 #ifndef DISABLE_PERFCOUNTERS
1372 mono_perfcounters_init ();
1375 mono_counters_register ("Max native code in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_size);
1376 mono_counters_register ("Max code space allocated in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_alloc);
1377 mono_counters_register ("Total code space allocated", MONO_COUNTER_INT|MONO_COUNTER_JIT, &total_domain_code_alloc);
1379 mono_gc_base_init ();
1381 MONO_FAST_TLS_INIT (tls_appdomain);
1382 mono_native_tls_alloc (&appdomain_thread_id, NULL);
1384 InitializeCriticalSection (&appdomains_mutex);
1386 mono_metadata_init ();
1387 mono_images_init ();
1388 mono_assemblies_init ();
1389 mono_classes_init ();
1390 mono_loader_init ();
1391 mono_reflection_init ();
1392 mono_runtime_init_tls ();
1394 /* FIXME: When should we release this memory? */
1395 MONO_GC_REGISTER_ROOT_FIXED (appdomains_list);
1397 domain = mono_domain_create ();
1398 mono_root_domain = domain;
1400 SET_APPDOMAIN (domain);
1402 /* Get a list of runtimes supported by the exe */
1403 if (exe_filename != NULL) {
1405 * This function will load the exe file as a MonoImage. We need to close it, but
1406 * that would mean it would be reloaded later. So instead, we save it to
1407 * exe_image, and close it during shutdown.
1409 get_runtimes_from_exe (exe_filename, &exe_image, runtimes);
1412 exe_image = mono_assembly_open_from_bundle (exe_filename, NULL, FALSE);
1414 exe_image = mono_image_open (exe_filename, NULL);
1416 mono_fixup_exe_image (exe_image);
1418 } else if (runtime_version != NULL) {
1419 runtimes [0] = get_runtime_by_version (runtime_version);
1420 runtimes [1] = NULL;
1423 if (runtimes [0] == NULL) {
1424 const MonoRuntimeInfo *default_runtime = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
1425 runtimes [0] = default_runtime;
1426 runtimes [1] = NULL;
1427 g_print ("WARNING: The runtime version supported by this application is unavailable.\n");
1428 g_print ("Using default runtime: %s\n", default_runtime->runtime_version);
1431 /* The selected runtime will be the first one for which there is a mscrolib.dll */
1432 for (n = 0; runtimes [n] != NULL && ass == NULL; n++) {
1433 current_runtime = runtimes [n];
1434 ass = mono_assembly_load_corlib (current_runtime, &status);
1435 if (status != MONO_IMAGE_OK && status != MONO_IMAGE_ERROR_ERRNO)
1440 if ((status != MONO_IMAGE_OK) || (ass == NULL)) {
1442 case MONO_IMAGE_ERROR_ERRNO: {
1443 char *corlib_file = g_build_filename (mono_assembly_getrootdir (), "mono", current_runtime->framework_version, "mscorlib.dll", NULL);
1444 g_print ("The assembly mscorlib.dll was not found or could not be loaded.\n");
1445 g_print ("It should have been installed in the `%s' directory.\n", corlib_file);
1446 g_free (corlib_file);
1449 case MONO_IMAGE_IMAGE_INVALID:
1450 g_print ("The file %s/mscorlib.dll is an invalid CIL image\n",
1451 mono_assembly_getrootdir ());
1453 case MONO_IMAGE_MISSING_ASSEMBLYREF:
1454 g_print ("Missing assembly reference in %s/mscorlib.dll\n",
1455 mono_assembly_getrootdir ());
1458 /* to suppress compiler warning */
1464 mono_defaults.corlib = mono_assembly_get_image (ass);
1466 mono_defaults.object_class = mono_class_from_name (
1467 mono_defaults.corlib, "System", "Object");
1468 g_assert (mono_defaults.object_class != 0);
1470 mono_defaults.void_class = mono_class_from_name (
1471 mono_defaults.corlib, "System", "Void");
1472 g_assert (mono_defaults.void_class != 0);
1474 mono_defaults.boolean_class = mono_class_from_name (
1475 mono_defaults.corlib, "System", "Boolean");
1476 g_assert (mono_defaults.boolean_class != 0);
1478 mono_defaults.byte_class = mono_class_from_name (
1479 mono_defaults.corlib, "System", "Byte");
1480 g_assert (mono_defaults.byte_class != 0);
1482 mono_defaults.sbyte_class = mono_class_from_name (
1483 mono_defaults.corlib, "System", "SByte");
1484 g_assert (mono_defaults.sbyte_class != 0);
1486 mono_defaults.int16_class = mono_class_from_name (
1487 mono_defaults.corlib, "System", "Int16");
1488 g_assert (mono_defaults.int16_class != 0);
1490 mono_defaults.uint16_class = mono_class_from_name (
1491 mono_defaults.corlib, "System", "UInt16");
1492 g_assert (mono_defaults.uint16_class != 0);
1494 mono_defaults.int32_class = mono_class_from_name (
1495 mono_defaults.corlib, "System", "Int32");
1496 g_assert (mono_defaults.int32_class != 0);
1498 mono_defaults.uint32_class = mono_class_from_name (
1499 mono_defaults.corlib, "System", "UInt32");
1500 g_assert (mono_defaults.uint32_class != 0);
1502 mono_defaults.uint_class = mono_class_from_name (
1503 mono_defaults.corlib, "System", "UIntPtr");
1504 g_assert (mono_defaults.uint_class != 0);
1506 mono_defaults.int_class = mono_class_from_name (
1507 mono_defaults.corlib, "System", "IntPtr");
1508 g_assert (mono_defaults.int_class != 0);
1510 mono_defaults.int64_class = mono_class_from_name (
1511 mono_defaults.corlib, "System", "Int64");
1512 g_assert (mono_defaults.int64_class != 0);
1514 mono_defaults.uint64_class = mono_class_from_name (
1515 mono_defaults.corlib, "System", "UInt64");
1516 g_assert (mono_defaults.uint64_class != 0);
1518 mono_defaults.single_class = mono_class_from_name (
1519 mono_defaults.corlib, "System", "Single");
1520 g_assert (mono_defaults.single_class != 0);
1522 mono_defaults.double_class = mono_class_from_name (
1523 mono_defaults.corlib, "System", "Double");
1524 g_assert (mono_defaults.double_class != 0);
1526 mono_defaults.char_class = mono_class_from_name (
1527 mono_defaults.corlib, "System", "Char");
1528 g_assert (mono_defaults.char_class != 0);
1530 mono_defaults.string_class = mono_class_from_name (
1531 mono_defaults.corlib, "System", "String");
1532 g_assert (mono_defaults.string_class != 0);
1534 mono_defaults.enum_class = mono_class_from_name (
1535 mono_defaults.corlib, "System", "Enum");
1536 g_assert (mono_defaults.enum_class != 0);
1538 mono_defaults.array_class = mono_class_from_name (
1539 mono_defaults.corlib, "System", "Array");
1540 g_assert (mono_defaults.array_class != 0);
1542 mono_defaults.delegate_class = mono_class_from_name (
1543 mono_defaults.corlib, "System", "Delegate");
1544 g_assert (mono_defaults.delegate_class != 0 );
1546 mono_defaults.multicastdelegate_class = mono_class_from_name (
1547 mono_defaults.corlib, "System", "MulticastDelegate");
1548 g_assert (mono_defaults.multicastdelegate_class != 0 );
1550 mono_defaults.asyncresult_class = mono_class_from_name (
1551 mono_defaults.corlib, "System.Runtime.Remoting.Messaging",
1553 g_assert (mono_defaults.asyncresult_class != 0 );
1555 mono_defaults.manualresetevent_class = mono_class_from_name (
1556 mono_defaults.corlib, "System.Threading", "ManualResetEvent");
1557 g_assert (mono_defaults.manualresetevent_class != 0 );
1559 mono_defaults.typehandle_class = mono_class_from_name (
1560 mono_defaults.corlib, "System", "RuntimeTypeHandle");
1561 g_assert (mono_defaults.typehandle_class != 0);
1563 mono_defaults.methodhandle_class = mono_class_from_name (
1564 mono_defaults.corlib, "System", "RuntimeMethodHandle");
1565 g_assert (mono_defaults.methodhandle_class != 0);
1567 mono_defaults.fieldhandle_class = mono_class_from_name (
1568 mono_defaults.corlib, "System", "RuntimeFieldHandle");
1569 g_assert (mono_defaults.fieldhandle_class != 0);
1571 mono_defaults.systemtype_class = mono_class_from_name (
1572 mono_defaults.corlib, "System", "Type");
1573 g_assert (mono_defaults.systemtype_class != 0);
1575 mono_defaults.monotype_class = mono_class_from_name (
1576 mono_defaults.corlib, "System", "MonoType");
1577 g_assert (mono_defaults.monotype_class != 0);
1579 mono_defaults.exception_class = mono_class_from_name (
1580 mono_defaults.corlib, "System", "Exception");
1581 g_assert (mono_defaults.exception_class != 0);
1583 mono_defaults.threadabortexception_class = mono_class_from_name (
1584 mono_defaults.corlib, "System.Threading", "ThreadAbortException");
1585 g_assert (mono_defaults.threadabortexception_class != 0);
1587 mono_defaults.thread_class = mono_class_from_name (
1588 mono_defaults.corlib, "System.Threading", "Thread");
1589 g_assert (mono_defaults.thread_class != 0);
1591 mono_defaults.internal_thread_class = mono_class_from_name (
1592 mono_defaults.corlib, "System.Threading", "InternalThread");
1593 if (!mono_defaults.internal_thread_class) {
1594 /* This can happen with an old mscorlib */
1595 fprintf (stderr, "Corlib too old for this runtime.\n");
1596 fprintf (stderr, "Loaded from: %s\n",
1597 mono_defaults.corlib? mono_image_get_filename (mono_defaults.corlib): "unknown");
1601 mono_defaults.appdomain_class = mono_class_from_name (
1602 mono_defaults.corlib, "System", "AppDomain");
1603 g_assert (mono_defaults.appdomain_class != 0);
1605 #ifndef DISABLE_REMOTING
1606 mono_defaults.transparent_proxy_class = mono_class_from_name (
1607 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "TransparentProxy");
1608 g_assert (mono_defaults.transparent_proxy_class != 0);
1610 mono_defaults.real_proxy_class = mono_class_from_name (
1611 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "RealProxy");
1612 g_assert (mono_defaults.real_proxy_class != 0);
1614 mono_defaults.marshalbyrefobject_class = mono_class_from_name (
1615 mono_defaults.corlib, "System", "MarshalByRefObject");
1616 g_assert (mono_defaults.marshalbyrefobject_class != 0);
1618 mono_defaults.iremotingtypeinfo_class = mono_class_from_name (
1619 mono_defaults.corlib, "System.Runtime.Remoting", "IRemotingTypeInfo");
1620 g_assert (mono_defaults.iremotingtypeinfo_class != 0);
1623 mono_defaults.mono_method_message_class = mono_class_from_name (
1624 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", "MonoMethodMessage");
1625 g_assert (mono_defaults.mono_method_message_class != 0);
1627 mono_defaults.field_info_class = mono_class_from_name (
1628 mono_defaults.corlib, "System.Reflection", "FieldInfo");
1629 g_assert (mono_defaults.field_info_class != 0);
1631 mono_defaults.method_info_class = mono_class_from_name (
1632 mono_defaults.corlib, "System.Reflection", "MethodInfo");
1633 g_assert (mono_defaults.method_info_class != 0);
1635 mono_defaults.stringbuilder_class = mono_class_from_name (
1636 mono_defaults.corlib, "System.Text", "StringBuilder");
1637 g_assert (mono_defaults.stringbuilder_class != 0);
1639 mono_defaults.math_class = mono_class_from_name (
1640 mono_defaults.corlib, "System", "Math");
1641 g_assert (mono_defaults.math_class != 0);
1643 mono_defaults.stack_frame_class = mono_class_from_name (
1644 mono_defaults.corlib, "System.Diagnostics", "StackFrame");
1645 g_assert (mono_defaults.stack_frame_class != 0);
1647 mono_defaults.stack_trace_class = mono_class_from_name (
1648 mono_defaults.corlib, "System.Diagnostics", "StackTrace");
1649 g_assert (mono_defaults.stack_trace_class != 0);
1651 mono_defaults.marshal_class = mono_class_from_name (
1652 mono_defaults.corlib, "System.Runtime.InteropServices", "Marshal");
1653 g_assert (mono_defaults.marshal_class != 0);
1655 mono_defaults.typed_reference_class = mono_class_from_name (
1656 mono_defaults.corlib, "System", "TypedReference");
1657 g_assert (mono_defaults.typed_reference_class != 0);
1659 mono_defaults.argumenthandle_class = mono_class_from_name (
1660 mono_defaults.corlib, "System", "RuntimeArgumentHandle");
1661 g_assert (mono_defaults.argumenthandle_class != 0);
1663 mono_defaults.monitor_class = mono_class_from_name (
1664 mono_defaults.corlib, "System.Threading", "Monitor");
1665 g_assert (mono_defaults.monitor_class != 0);
1667 mono_defaults.runtimesecurityframe_class = mono_class_from_name (
1668 mono_defaults.corlib, "System.Security", "RuntimeSecurityFrame");
1670 mono_defaults.executioncontext_class = mono_class_from_name (
1671 mono_defaults.corlib, "System.Threading", "ExecutionContext");
1673 mono_defaults.internals_visible_class = mono_class_from_name (
1674 mono_defaults.corlib, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute");
1676 mono_defaults.critical_finalizer_object = mono_class_from_name (
1677 mono_defaults.corlib, "System.Runtime.ConstrainedExecution", "CriticalFinalizerObject");
1680 * mscorlib needs a little help, only now it can load its friends list (after we have
1681 * loaded the InternalsVisibleToAttribute), load it now
1683 mono_assembly_load_friends (ass);
1685 mono_defaults.safehandle_class = mono_class_from_name (
1686 mono_defaults.corlib, "System.Runtime.InteropServices", "SafeHandle");
1688 mono_defaults.handleref_class = mono_class_from_name (
1689 mono_defaults.corlib, "System.Runtime.InteropServices", "HandleRef");
1691 mono_defaults.attribute_class = mono_class_from_name (
1692 mono_defaults.corlib, "System", "Attribute");
1694 mono_defaults.customattribute_data_class = mono_class_from_name (
1695 mono_defaults.corlib, "System.Reflection", "CustomAttributeData");
1697 /* these are initialized lazily when COM features are used */
1699 mono_class_init (mono_defaults.array_class);
1700 mono_defaults.generic_nullable_class = mono_class_from_name (
1701 mono_defaults.corlib, "System", "Nullable`1");
1702 mono_defaults.generic_ilist_class = mono_class_from_name (
1703 mono_defaults.corlib, "System.Collections.Generic", "IList`1");
1704 mono_defaults.generic_ireadonlylist_class = mono_class_from_name (
1705 mono_defaults.corlib, "System.Collections.Generic", "IReadOnlyList`1");
1707 domain->friendly_name = g_path_get_basename (filename);
1709 _mono_debug_init_corlib (domain);
1717 * Creates the initial application domain and initializes the mono_defaults
1719 * This function is guaranteed to not run any IL code.
1720 * The runtime is initialized using the default runtime version.
1722 * Returns: the initial domain.
1725 mono_init (const char *domain_name)
1727 return mono_init_internal (domain_name, NULL, DEFAULT_RUNTIME_VERSION);
1731 * mono_init_from_assembly:
1732 * @domain_name: name to give to the initial domain
1733 * @filename: filename to load on startup
1735 * Used by the runtime, users should use mono_jit_init instead.
1737 * Creates the initial application domain and initializes the mono_defaults
1739 * This function is guaranteed to not run any IL code.
1740 * The runtime is initialized using the runtime version required by the
1741 * provided executable. The version is determined by looking at the exe
1742 * configuration file and the version PE field)
1744 * Returns: the initial domain.
1747 mono_init_from_assembly (const char *domain_name, const char *filename)
1749 return mono_init_internal (domain_name, filename, NULL);
1753 * mono_init_version:
1755 * Used by the runtime, users should use mono_jit_init instead.
1757 * Creates the initial application domain and initializes the mono_defaults
1760 * This function is guaranteed to not run any IL code.
1761 * The runtime is initialized using the provided rutime version.
1763 * Returns: the initial domain.
1766 mono_init_version (const char *domain_name, const char *version)
1768 return mono_init_internal (domain_name, NULL, version);
1774 * Cleans up all metadata modules.
1779 mono_close_exe_image ();
1781 mono_defaults.corlib = NULL;
1783 mono_config_cleanup ();
1784 mono_loader_cleanup ();
1785 mono_classes_cleanup ();
1786 mono_assemblies_cleanup ();
1787 mono_images_cleanup ();
1788 mono_debug_cleanup ();
1789 mono_metadata_cleanup ();
1791 mono_native_tls_free (appdomain_thread_id);
1792 DeleteCriticalSection (&appdomains_mutex);
1800 mono_close_exe_image (void)
1803 mono_image_close (exe_image);
1807 * mono_get_root_domain:
1809 * The root AppDomain is the initial domain created by the runtime when it is
1810 * initialized. Programs execute on this AppDomain, but can create new ones
1811 * later. Currently there is no unmanaged API to create new AppDomains, this
1812 * must be done from managed code.
1814 * Returns: the root appdomain, to obtain the current domain, use mono_domain_get ()
1817 mono_get_root_domain (void)
1819 return mono_root_domain;
1825 * Returns: the current domain, to obtain the root domain use
1826 * mono_get_root_domain().
1831 return GET_APPDOMAIN ();
1835 mono_domain_unset (void)
1837 SET_APPDOMAIN (NULL);
1841 mono_domain_set_internal_with_options (MonoDomain *domain, gboolean migrate_exception)
1843 MonoInternalThread *thread;
1845 if (mono_domain_get () == domain)
1848 SET_APPDOMAIN (domain);
1849 SET_APPCONTEXT (domain->default_context);
1851 if (migrate_exception) {
1852 thread = mono_thread_internal_current ();
1853 if (!thread->abort_exc)
1856 g_assert (thread->abort_exc->object.vtable->domain != domain);
1857 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
1858 g_assert (thread->abort_exc->object.vtable->domain == domain);
1863 * mono_domain_set_internal:
1864 * @domain: the new domain
1866 * Sets the current domain to @domain.
1869 mono_domain_set_internal (MonoDomain *domain)
1871 mono_domain_set_internal_with_options (domain, TRUE);
1875 mono_domain_foreach (MonoDomainFunc func, gpointer user_data)
1881 * Create a copy of the data to avoid calling the user callback
1882 * inside the lock because that could lead to deadlocks.
1883 * We can do this because this function is not perf. critical.
1885 mono_appdomains_lock ();
1886 size = appdomain_list_size;
1887 copy = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1888 memcpy (copy, appdomains_list, appdomain_list_size * sizeof (void*));
1889 mono_appdomains_unlock ();
1891 for (i = 0; i < size; ++i) {
1893 func (copy [i], user_data);
1896 mono_gc_free_fixed (copy);
1900 * mono_domain_assembly_open:
1901 * @domain: the application domain
1902 * @name: file name of the assembly
1904 * fixme: maybe we should integrate this with mono_assembly_open ??
1907 mono_domain_assembly_open (MonoDomain *domain, const char *name)
1909 MonoDomain *current;
1913 mono_domain_assemblies_lock (domain);
1914 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1916 if (strcmp (name, ass->aname.name) == 0) {
1917 mono_domain_assemblies_unlock (domain);
1921 mono_domain_assemblies_unlock (domain);
1923 if (domain != mono_domain_get ()) {
1924 current = mono_domain_get ();
1926 mono_domain_set (domain, FALSE);
1927 ass = mono_assembly_open (name, NULL);
1928 mono_domain_set (current, FALSE);
1930 ass = mono_assembly_open (name, NULL);
1937 unregister_vtable_reflection_type (MonoVTable *vtable)
1939 MonoObject *type = vtable->type;
1941 if (type->vtable->klass != mono_defaults.monotype_class)
1942 MONO_GC_UNREGISTER_ROOT_IF_MOVING (vtable->type);
1946 mono_domain_free (MonoDomain *domain, gboolean force)
1948 int code_size, code_alloc;
1952 if ((domain == mono_root_domain) && !force) {
1953 g_warning ("cant unload root domain");
1957 if (mono_dont_free_domains)
1960 mono_profiler_appdomain_event (domain, MONO_PROFILE_START_UNLOAD);
1962 mono_debug_domain_unload (domain);
1964 mono_appdomains_lock ();
1965 appdomains_list [domain->domain_id] = NULL;
1966 mono_appdomains_unlock ();
1968 /* must do this early as it accesses fields and types */
1969 if (domain->special_static_fields) {
1970 mono_alloc_special_static_data_free (domain->special_static_fields);
1971 g_hash_table_destroy (domain->special_static_fields);
1972 domain->special_static_fields = NULL;
1976 * We must destroy all these hash tables here because they
1977 * contain references to managed objects belonging to the
1978 * domain. Once we let the GC clear the domain there must be
1979 * no more such references, or we'll crash if a collection
1982 mono_g_hash_table_destroy (domain->ldstr_table);
1983 domain->ldstr_table = NULL;
1985 mono_g_hash_table_destroy (domain->env);
1988 if (domain->tlsrec_list) {
1989 mono_thread_destroy_domain_tls (domain);
1990 domain->tlsrec_list = NULL;
1993 mono_reflection_cleanup_domain (domain);
1995 /* This must be done before type_hash is freed */
1996 if (domain->class_vtable_array) {
1998 for (i = 0; i < domain->class_vtable_array->len; ++i)
1999 unregister_vtable_reflection_type (g_ptr_array_index (domain->class_vtable_array, i));
2002 if (domain->type_hash) {
2003 mono_g_hash_table_destroy (domain->type_hash);
2004 domain->type_hash = NULL;
2006 if (domain->type_init_exception_hash) {
2007 mono_g_hash_table_destroy (domain->type_init_exception_hash);
2008 domain->type_init_exception_hash = NULL;
2011 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2012 MonoAssembly *ass = tmp->data;
2013 mono_assembly_release_gc_roots (ass);
2016 /* Have to zero out reference fields since they will be invalidated by the clear_domain () call below */
2017 for (p = (gpointer*)&domain->MONO_DOMAIN_FIRST_OBJECT; p < (gpointer*)&domain->MONO_DOMAIN_FIRST_GC_TRACKED; ++p)
2020 /* This needs to be done before closing assemblies */
2021 mono_gc_clear_domain (domain);
2023 /* Close dynamic assemblies first, since they have no ref count */
2024 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2025 MonoAssembly *ass = tmp->data;
2026 if (!ass->image || !image_is_dynamic (ass->image))
2028 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);
2029 if (!mono_assembly_close_except_image_pools (ass))
2033 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2034 MonoAssembly *ass = tmp->data;
2037 if (!ass->image || image_is_dynamic (ass->image))
2039 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);
2040 if (!mono_assembly_close_except_image_pools (ass))
2044 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2045 MonoAssembly *ass = tmp->data;
2047 mono_assembly_close_finish (ass);
2049 g_slist_free (domain->domain_assemblies);
2050 domain->domain_assemblies = NULL;
2053 * Send this after the assemblies have been unloaded and the domain is still in a
2056 mono_profiler_appdomain_event (domain, MONO_PROFILE_END_UNLOAD);
2058 if (free_domain_hook)
2059 free_domain_hook (domain);
2061 /* FIXME: free delegate_hash_table when it's used */
2062 if (domain->search_path) {
2063 g_strfreev (domain->search_path);
2064 domain->search_path = NULL;
2066 domain->create_proxy_for_type_method = NULL;
2067 domain->private_invoke_method = NULL;
2068 domain->default_context = NULL;
2069 domain->out_of_memory_ex = NULL;
2070 domain->null_reference_ex = NULL;
2071 domain->stack_overflow_ex = NULL;
2072 domain->ephemeron_tombstone = NULL;
2073 domain->entry_assembly = NULL;
2075 g_free (domain->friendly_name);
2076 domain->friendly_name = NULL;
2077 g_ptr_array_free (domain->class_vtable_array, TRUE);
2078 domain->class_vtable_array = NULL;
2079 g_hash_table_destroy (domain->proxy_vtable_hash);
2080 domain->proxy_vtable_hash = NULL;
2081 if (domain->static_data_array) {
2082 mono_gc_free_fixed (domain->static_data_array);
2083 domain->static_data_array = NULL;
2085 mono_internal_hash_table_destroy (&domain->jit_code_hash);
2088 * There might still be jit info tables of this domain which
2089 * are not freed. Since the domain cannot be in use anymore,
2090 * this will free them.
2092 mono_thread_hazardous_try_free_all ();
2093 if (domain->aot_modules)
2094 jit_info_table_free (domain->aot_modules);
2095 g_assert (domain->num_jit_info_tables == 1);
2096 jit_info_table_free (domain->jit_info_table);
2097 domain->jit_info_table = NULL;
2098 g_assert (!domain->jit_info_free_queue);
2100 /* collect statistics */
2101 code_alloc = mono_code_manager_size (domain->code_mp, &code_size);
2102 total_domain_code_alloc += code_alloc;
2103 max_domain_code_alloc = MAX (max_domain_code_alloc, code_alloc);
2104 max_domain_code_size = MAX (max_domain_code_size, code_size);
2106 if (debug_domain_unload) {
2107 mono_mempool_invalidate (domain->mp);
2108 mono_code_manager_invalidate (domain->code_mp);
2110 #ifndef DISABLE_PERFCOUNTERS
2111 mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (domain->mp);
2113 mono_mempool_destroy (domain->mp);
2115 mono_code_manager_destroy (domain->code_mp);
2116 domain->code_mp = NULL;
2118 lock_free_mempool_free (domain->lock_free_mp);
2119 domain->lock_free_mp = NULL;
2121 g_hash_table_destroy (domain->finalizable_objects_hash);
2122 domain->finalizable_objects_hash = NULL;
2123 if (domain->method_rgctx_hash) {
2124 g_hash_table_destroy (domain->method_rgctx_hash);
2125 domain->method_rgctx_hash = NULL;
2127 if (domain->generic_virtual_cases) {
2128 g_hash_table_destroy (domain->generic_virtual_cases);
2129 domain->generic_virtual_cases = NULL;
2131 if (domain->generic_virtual_thunks) {
2132 g_hash_table_destroy (domain->generic_virtual_thunks);
2133 domain->generic_virtual_thunks = NULL;
2135 if (domain->ftnptrs_hash) {
2136 g_hash_table_destroy (domain->ftnptrs_hash);
2137 domain->ftnptrs_hash = NULL;
2140 DeleteCriticalSection (&domain->finalizable_objects_hash_lock);
2141 DeleteCriticalSection (&domain->assemblies_lock);
2142 DeleteCriticalSection (&domain->jit_code_hash_lock);
2143 DeleteCriticalSection (&domain->lock);
2144 domain->setup = NULL;
2146 mono_gc_deregister_root ((char*)&(domain->MONO_DOMAIN_FIRST_GC_TRACKED));
2148 /* FIXME: anything else required ? */
2150 mono_gc_free_fixed (domain);
2152 #ifndef DISABLE_PERFCOUNTERS
2153 mono_perfcounters->loader_appdomains--;
2156 if (domain == mono_root_domain)
2157 mono_root_domain = NULL;
2161 * mono_domain_get_id:
2164 * Returns: the a domain for a specific domain id.
2167 mono_domain_get_by_id (gint32 domainid)
2169 MonoDomain * domain;
2171 mono_appdomains_lock ();
2172 if (domainid < appdomain_list_size)
2173 domain = appdomains_list [domainid];
2176 mono_appdomains_unlock ();
2182 mono_domain_get_id (MonoDomain *domain)
2184 return domain->domain_id;
2188 * mono_domain_alloc:
2190 * LOCKING: Acquires the domain lock.
2193 mono_domain_alloc (MonoDomain *domain, guint size)
2197 mono_domain_lock (domain);
2198 #ifndef DISABLE_PERFCOUNTERS
2199 mono_perfcounters->loader_bytes += size;
2201 res = mono_mempool_alloc (domain->mp, size);
2202 mono_domain_unlock (domain);
2208 * mono_domain_alloc0:
2210 * LOCKING: Acquires the domain lock.
2213 mono_domain_alloc0 (MonoDomain *domain, guint size)
2217 mono_domain_lock (domain);
2218 #ifndef DISABLE_PERFCOUNTERS
2219 mono_perfcounters->loader_bytes += size;
2221 res = mono_mempool_alloc0 (domain->mp, size);
2222 mono_domain_unlock (domain);
2228 mono_domain_alloc0_lock_free (MonoDomain *domain, guint size)
2230 return lock_free_mempool_alloc0 (domain->lock_free_mp, size);
2234 * mono_domain_code_reserve:
2236 * LOCKING: Acquires the domain lock.
2239 mono_domain_code_reserve (MonoDomain *domain, int size)
2243 mono_domain_lock (domain);
2244 res = mono_code_manager_reserve (domain->code_mp, size);
2245 mono_domain_unlock (domain);
2251 * mono_domain_code_reserve_align:
2253 * LOCKING: Acquires the domain lock.
2256 mono_domain_code_reserve_align (MonoDomain *domain, int size, int alignment)
2260 mono_domain_lock (domain);
2261 res = mono_code_manager_reserve_align (domain->code_mp, size, alignment);
2262 mono_domain_unlock (domain);
2268 * mono_domain_code_commit:
2270 * LOCKING: Acquires the domain lock.
2273 mono_domain_code_commit (MonoDomain *domain, void *data, int size, int newsize)
2275 mono_domain_lock (domain);
2276 mono_code_manager_commit (domain->code_mp, data, size, newsize);
2277 mono_domain_unlock (domain);
2280 #if defined(__native_client_codegen__) && defined(__native_client__)
2282 * Given the temporary buffer (allocated by mono_domain_code_reserve) into which
2283 * we are generating code, return a pointer to the destination in the dynamic
2284 * code segment into which the code will be copied when mono_domain_code_commit
2286 * LOCKING: Acquires the domain lock.
2289 nacl_domain_get_code_dest (MonoDomain *domain, void *data)
2292 mono_domain_lock (domain);
2293 dest = nacl_code_manager_get_code_dest (domain->code_mp, data);
2294 mono_domain_unlock (domain);
2299 * Convenience function which calls mono_domain_code_commit to validate and copy
2300 * the code. The caller sets *buf_base and *buf_size to the start and size of
2301 * the buffer (allocated by mono_domain_code_reserve), and *code_end to the byte
2302 * after the last instruction byte. On return, *buf_base will point to the start
2303 * of the copied in the code segment, and *code_end will point after the end of
2307 nacl_domain_code_validate (MonoDomain *domain, guint8 **buf_base, int buf_size, guint8 **code_end)
2309 guint8 *tmp = nacl_domain_get_code_dest (domain, *buf_base);
2310 mono_domain_code_commit (domain, *buf_base, buf_size, *code_end - *buf_base);
2311 *code_end = tmp + (*code_end - *buf_base);
2317 /* no-op versions of Native Client functions */
2320 nacl_domain_get_code_dest (MonoDomain *domain, void *data)
2326 nacl_domain_code_validate (MonoDomain *domain, guint8 **buf_base, int buf_size, guint8 **code_end)
2333 * mono_domain_code_foreach:
2334 * Iterate over the code thunks of the code manager of @domain.
2336 * The @func callback MUST not take any locks. If it really needs to, it must respect
2337 * the locking rules of the runtime: http://www.mono-project.com/Mono:Runtime:Documentation:ThreadSafety
2338 * LOCKING: Acquires the domain lock.
2342 mono_domain_code_foreach (MonoDomain *domain, MonoCodeManagerFunc func, void *user_data)
2344 mono_domain_lock (domain);
2345 mono_code_manager_foreach (domain->code_mp, func, user_data);
2346 mono_domain_unlock (domain);
2351 mono_context_set (MonoAppContext * new_context)
2353 SET_APPCONTEXT (new_context);
2357 mono_context_get (void)
2359 return GET_APPCONTEXT ();
2362 /* LOCKING: the caller holds the lock for this domain */
2364 mono_domain_add_class_static_data (MonoDomain *domain, MonoClass *klass, gpointer data, guint32 *bitmap)
2366 /* The first entry in the array is the index of the next free slot
2367 * and the total size of the array
2370 if (domain->static_data_array) {
2371 int size = GPOINTER_TO_INT (domain->static_data_array [1]);
2372 next = GPOINTER_TO_INT (domain->static_data_array [0]);
2374 /* 'data' is allocated by alloc_fixed */
2375 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * (size * 2), MONO_GC_ROOT_DESCR_FOR_FIXED (size * 2));
2376 mono_gc_memmove_aligned (new_array, domain->static_data_array, sizeof (gpointer) * size);
2378 new_array [1] = GINT_TO_POINTER (size);
2379 mono_gc_free_fixed (domain->static_data_array);
2380 domain->static_data_array = new_array;
2384 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * size, MONO_GC_ROOT_DESCR_FOR_FIXED (size));
2386 new_array [0] = GINT_TO_POINTER (next);
2387 new_array [1] = GINT_TO_POINTER (size);
2388 domain->static_data_array = new_array;
2390 domain->static_data_array [next++] = data;
2391 domain->static_data_array [0] = GINT_TO_POINTER (next);
2395 mono_get_corlib (void)
2397 return mono_defaults.corlib;
2401 mono_get_object_class (void)
2403 return mono_defaults.object_class;
2407 mono_get_byte_class (void)
2409 return mono_defaults.byte_class;
2413 mono_get_void_class (void)
2415 return mono_defaults.void_class;
2419 mono_get_boolean_class (void)
2421 return mono_defaults.boolean_class;
2425 mono_get_sbyte_class (void)
2427 return mono_defaults.sbyte_class;
2431 mono_get_int16_class (void)
2433 return mono_defaults.int16_class;
2437 mono_get_uint16_class (void)
2439 return mono_defaults.uint16_class;
2443 mono_get_int32_class (void)
2445 return mono_defaults.int32_class;
2449 mono_get_uint32_class (void)
2451 return mono_defaults.uint32_class;
2455 mono_get_intptr_class (void)
2457 return mono_defaults.int_class;
2461 mono_get_uintptr_class (void)
2463 return mono_defaults.uint_class;
2467 mono_get_int64_class (void)
2469 return mono_defaults.int64_class;
2473 mono_get_uint64_class (void)
2475 return mono_defaults.uint64_class;
2479 mono_get_single_class (void)
2481 return mono_defaults.single_class;
2485 mono_get_double_class (void)
2487 return mono_defaults.double_class;
2491 mono_get_char_class (void)
2493 return mono_defaults.char_class;
2497 mono_get_string_class (void)
2499 return mono_defaults.string_class;
2503 mono_get_enum_class (void)
2505 return mono_defaults.enum_class;
2509 mono_get_array_class (void)
2511 return mono_defaults.array_class;
2515 mono_get_thread_class (void)
2517 return mono_defaults.thread_class;
2521 mono_get_exception_class (void)
2523 return mono_defaults.exception_class;
2527 static char* get_attribute_value (const gchar **attribute_names,
2528 const gchar **attribute_values,
2529 const char *att_name)
2532 for (n=0; attribute_names[n] != NULL; n++) {
2533 if (strcmp (attribute_names[n], att_name) == 0)
2534 return g_strdup (attribute_values[n]);
2539 static void start_element (GMarkupParseContext *context,
2540 const gchar *element_name,
2541 const gchar **attribute_names,
2542 const gchar **attribute_values,
2546 AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2548 if (strcmp (element_name, "configuration") == 0) {
2549 app_config->configuration_count++;
2552 if (strcmp (element_name, "startup") == 0) {
2553 app_config->startup_count++;
2557 if (app_config->configuration_count != 1 || app_config->startup_count != 1)
2560 if (strcmp (element_name, "requiredRuntime") == 0) {
2561 app_config->required_runtime = get_attribute_value (attribute_names, attribute_values, "version");
2562 } else if (strcmp (element_name, "supportedRuntime") == 0) {
2563 char *version = get_attribute_value (attribute_names, attribute_values, "version");
2564 app_config->supported_runtimes = g_slist_append (app_config->supported_runtimes, version);
2568 static void end_element (GMarkupParseContext *context,
2569 const gchar *element_name,
2573 AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2575 if (strcmp (element_name, "configuration") == 0) {
2576 app_config->configuration_count--;
2577 } else if (strcmp (element_name, "startup") == 0) {
2578 app_config->startup_count--;
2582 static const GMarkupParser
2591 static AppConfigInfo *
2592 app_config_parse (const char *exe_filename)
2594 AppConfigInfo *app_config;
2595 GMarkupParseContext *context;
2598 const char *bundled_config;
2599 char *config_filename;
2601 bundled_config = mono_config_string_for_assembly_file (exe_filename);
2603 if (bundled_config) {
2604 text = g_strdup (bundled_config);
2605 len = strlen (text);
2607 config_filename = g_strconcat (exe_filename, ".config", NULL);
2609 if (!g_file_get_contents (config_filename, &text, &len, NULL)) {
2610 g_free (config_filename);
2613 g_free (config_filename);
2616 app_config = g_new0 (AppConfigInfo, 1);
2618 context = g_markup_parse_context_new (&mono_parser, 0, app_config, NULL);
2619 if (g_markup_parse_context_parse (context, text, len, NULL)) {
2620 g_markup_parse_context_end_parse (context, NULL);
2622 g_markup_parse_context_free (context);
2628 app_config_free (AppConfigInfo* app_config)
2631 GSList *list = app_config->supported_runtimes;
2632 while (list != NULL) {
2633 rt = (char*)list->data;
2635 list = g_slist_next (list);
2637 g_slist_free (app_config->supported_runtimes);
2638 g_free (app_config->required_runtime);
2639 g_free (app_config);
2643 static const MonoRuntimeInfo*
2644 get_runtime_by_version (const char *version)
2647 int max = G_N_ELEMENTS (supported_runtimes);
2653 for (n=0; n<max; n++) {
2654 if (strcmp (version, supported_runtimes[n].runtime_version) == 0)
2655 return &supported_runtimes[n];
2658 vlen = strlen (version);
2659 if (vlen >= 4 && version [1] - '0' >= 4) {
2660 for (n=0; n<max; n++) {
2661 if (strncmp (version, supported_runtimes[n].runtime_version, 4) == 0)
2662 return &supported_runtimes[n];
2670 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes)
2672 AppConfigInfo* app_config;
2674 const MonoRuntimeInfo* runtime = NULL;
2675 MonoImage *image = NULL;
2677 app_config = app_config_parse (exe_file);
2679 if (app_config != NULL) {
2680 /* Check supportedRuntime elements, if none is supported, fail.
2681 * If there are no such elements, look for a requiredRuntime element.
2683 if (app_config->supported_runtimes != NULL) {
2685 GSList *list = app_config->supported_runtimes;
2686 while (list != NULL) {
2687 version = (char*) list->data;
2688 runtime = get_runtime_by_version (version);
2689 if (runtime != NULL)
2690 runtimes [n++] = runtime;
2691 list = g_slist_next (list);
2693 runtimes [n] = NULL;
2694 app_config_free (app_config);
2698 /* Check the requiredRuntime element. This is for 1.0 apps only. */
2699 if (app_config->required_runtime != NULL) {
2700 runtimes [0] = get_runtime_by_version (app_config->required_runtime);
2701 runtimes [1] = NULL;
2702 app_config_free (app_config);
2705 app_config_free (app_config);
2708 /* Look for a runtime with the exact version */
2709 image = mono_assembly_open_from_bundle (exe_file, NULL, FALSE);
2712 image = mono_image_open (exe_file, NULL);
2714 if (image == NULL) {
2715 /* The image is wrong or the file was not found. In this case return
2716 * a default runtime and leave to the initialization method the work of
2717 * reporting the error.
2719 runtimes [0] = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
2720 runtimes [1] = NULL;
2726 runtimes [0] = get_runtime_by_version (image->version);
2727 runtimes [1] = NULL;
2732 * mono_get_runtime_info:
2734 * Returns: the version of the current runtime instance.
2736 const MonoRuntimeInfo*
2737 mono_get_runtime_info (void)
2739 return current_runtime;
2743 mono_debugger_check_runtime_version (const char *filename)
2745 const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
2746 const MonoRuntimeInfo *rinfo;
2749 get_runtimes_from_exe (filename, &image, runtimes);
2750 rinfo = runtimes [0];
2753 return g_strdup_printf ("Cannot get runtime version from assembly `%s'", filename);
2755 if (rinfo != current_runtime)
2756 return g_strdup_printf ("The Mono Debugger is currently using the `%s' runtime, but "
2757 "the assembly `%s' requires version `%s'", current_runtime->runtime_version,
2758 filename, rinfo->runtime_version);
2764 * mono_framework_version:
2766 * Return the major version of the framework curently executing.
2769 mono_framework_version (void)
2771 return current_runtime->framework_version [0] - '0';
2775 mono_enable_debug_domain_unload (gboolean enable)
2777 debug_domain_unload = enable;