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)
163 MONO_THREAD_VAR_OFFSET (tls_appdomain, offset);
164 /* __asm ("jmp 1f; .section writetext, \"awx\"; 1: movl $tls_appdomain@ntpoff, %0; jmp 2f; .previous; 2:"
169 #define JIT_INFO_TABLE_FILL_RATIO_NOM 3
170 #define JIT_INFO_TABLE_FILL_RATIO_DENOM 4
171 #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)
173 #define JIT_INFO_TABLE_LOW_WATERMARK(n) ((n) / 2)
174 #define JIT_INFO_TABLE_HIGH_WATERMARK(n) ((n) * 5 / 6)
176 #define JIT_INFO_TOMBSTONE_MARKER ((MonoMethod*)NULL)
177 #define IS_JIT_INFO_TOMBSTONE(ji) ((ji)->d.method == JIT_INFO_TOMBSTONE_MARKER)
179 #define JIT_INFO_TABLE_HAZARD_INDEX 0
180 #define JIT_INFO_HAZARD_INDEX 1
183 jit_info_table_num_elements (MonoJitInfoTable *table)
186 int num_elements = 0;
188 for (i = 0; i < table->num_chunks; ++i) {
189 MonoJitInfoTableChunk *chunk = table->chunks [i];
190 int chunk_num_elements = chunk->num_elements;
193 for (j = 0; j < chunk_num_elements; ++j) {
194 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j]))
202 static MonoJitInfoTableChunk*
203 jit_info_table_new_chunk (void)
205 MonoJitInfoTableChunk *chunk = g_new0 (MonoJitInfoTableChunk, 1);
211 static MonoJitInfoTable *
212 jit_info_table_new (MonoDomain *domain)
214 MonoJitInfoTable *table = g_malloc0 (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*));
216 table->domain = domain;
217 table->num_chunks = 1;
218 table->chunks [0] = jit_info_table_new_chunk ();
224 jit_info_table_free (MonoJitInfoTable *table)
227 int num_chunks = table->num_chunks;
228 MonoDomain *domain = table->domain;
230 mono_domain_lock (domain);
232 table->domain->num_jit_info_tables--;
233 if (table->domain->num_jit_info_tables <= 1) {
236 for (list = table->domain->jit_info_free_queue; list; list = list->next)
239 g_slist_free (table->domain->jit_info_free_queue);
240 table->domain->jit_info_free_queue = NULL;
243 /* At this point we assume that there are no other threads
244 still accessing the table, so we don't have to worry about
245 hazardous pointers. */
247 for (i = 0; i < num_chunks; ++i) {
248 MonoJitInfoTableChunk *chunk = table->chunks [i];
252 if (--chunk->refcount > 0)
255 num_elements = chunk->num_elements;
256 for (j = 0; j < num_elements; ++j) {
257 MonoJitInfo *ji = chunk->data [j];
259 if (IS_JIT_INFO_TOMBSTONE (ji))
266 mono_domain_unlock (domain);
271 /* The jit_info_table is sorted in ascending order by the end
272 * addresses of the compiled methods. The reason why we have to do
273 * this is that once we introduce tombstones, it becomes possible for
274 * code ranges to overlap, and if we sort by code start and insert at
275 * the back of the table, we cannot guarantee that we won't overlook
278 * There are actually two possible ways to do the sorting and
279 * inserting which work with our lock-free mechanism:
281 * 1. Sort by start address and insert at the front. When looking for
282 * an entry, find the last one with a start address lower than the one
283 * you're looking for, then work your way to the front of the table.
285 * 2. Sort by end address and insert at the back. When looking for an
286 * entry, find the first one with an end address higher than the one
287 * you're looking for, then work your way to the end of the table.
289 * We chose the latter out of convenience.
292 jit_info_table_index (MonoJitInfoTable *table, gint8 *addr)
294 int left = 0, right = table->num_chunks;
296 g_assert (left < right);
299 int pos = (left + right) / 2;
300 MonoJitInfoTableChunk *chunk = table->chunks [pos];
302 if (addr < chunk->last_code_end)
306 } while (left < right);
307 g_assert (left == right);
309 if (left >= table->num_chunks)
310 return table->num_chunks - 1;
315 jit_info_table_chunk_index (MonoJitInfoTableChunk *chunk, MonoThreadHazardPointers *hp, gint8 *addr)
317 int left = 0, right = chunk->num_elements;
319 while (left < right) {
320 int pos = (left + right) / 2;
321 MonoJitInfo *ji = get_hazardous_pointer((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
322 gint8 *code_end = (gint8*)ji->code_start + ji->code_size;
329 g_assert (left == right);
335 jit_info_table_find (MonoJitInfoTable *table, MonoThreadHazardPointers *hp, gint8 *addr)
340 chunk_pos = jit_info_table_index (table, (gint8*)addr);
341 g_assert (chunk_pos < table->num_chunks);
343 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], hp, (gint8*)addr);
345 /* We now have a position that's very close to that of the
346 first element whose end address is higher than the one
347 we're looking for. If we don't have the exact position,
348 then we have a position below that one, so we'll just
349 search upward until we find our element. */
351 MonoJitInfoTableChunk *chunk = table->chunks [chunk_pos];
353 while (pos < chunk->num_elements) {
354 ji = get_hazardous_pointer ((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
358 if (IS_JIT_INFO_TOMBSTONE (ji)) {
359 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
362 if ((gint8*)addr >= (gint8*)ji->code_start
363 && (gint8*)addr < (gint8*)ji->code_start + ji->code_size) {
364 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
368 /* If we find a non-tombstone element which is already
369 beyond what we're looking for, we have to end the
371 if ((gint8*)addr < (gint8*)ji->code_start)
377 } while (chunk_pos < table->num_chunks);
381 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
386 * mono_jit_info_table_find_internal:
388 * If TRY_AOT is FALSE, avoid loading information for missing methods from AOT images, which is currently not async safe.
389 * In this case, only those AOT methods will be found whose jit info is already loaded.
390 * ASYNC SAFETY: When called in an async context (mono_thread_info_is_async_context ()), this is async safe.
391 * In this case, the returned MonoJitInfo might not have metadata information, in particular,
392 * mono_jit_info_get_method () could fail.
395 mono_jit_info_table_find_internal (MonoDomain *domain, char *addr, gboolean try_aot)
397 MonoJitInfoTable *table;
398 MonoJitInfo *ji, *module_ji;
399 MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
401 ++mono_stats.jit_info_table_lookup_count;
403 /* First we have to get the domain's jit_info_table. This is
404 complicated by the fact that a writer might substitute a
405 new table and free the old one. What the writer guarantees
406 us is that it looks at the hazard pointers after it has
407 changed the jit_info_table pointer. So, if we guard the
408 table by a hazard pointer and make sure that the pointer is
409 still there after we've made it hazardous, we don't have to
410 worry about the writer freeing the table. */
411 table = get_hazardous_pointer ((gpointer volatile*)&domain->jit_info_table, hp, JIT_INFO_TABLE_HAZARD_INDEX);
413 ji = jit_info_table_find (table, hp, (gint8*)addr);
415 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
419 /* Maybe its an AOT module */
420 if (try_aot && mono_root_domain && mono_root_domain->aot_modules) {
421 table = get_hazardous_pointer ((gpointer volatile*)&mono_root_domain->aot_modules, hp, JIT_INFO_TABLE_HAZARD_INDEX);
422 module_ji = jit_info_table_find (table, hp, (gint8*)addr);
424 ji = jit_info_find_in_aot_func (domain, module_ji->d.image, addr);
426 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
433 mono_jit_info_table_find (MonoDomain *domain, char *addr)
435 return mono_jit_info_table_find_internal (domain, addr, TRUE);
438 static G_GNUC_UNUSED void
439 jit_info_table_check (MonoJitInfoTable *table)
443 for (i = 0; i < table->num_chunks; ++i) {
444 MonoJitInfoTableChunk *chunk = table->chunks [i];
447 g_assert (chunk->refcount > 0 /* && chunk->refcount <= 8 */);
448 if (chunk->refcount > 10)
449 printf("warning: chunk refcount is %d\n", chunk->refcount);
450 g_assert (chunk->num_elements <= MONO_JIT_INFO_TABLE_CHUNK_SIZE);
452 for (j = 0; j < chunk->num_elements; ++j) {
453 MonoJitInfo *this = chunk->data [j];
456 g_assert ((gint8*)this->code_start + this->code_size <= chunk->last_code_end);
458 if (j < chunk->num_elements - 1)
459 next = chunk->data [j + 1];
460 else if (i < table->num_chunks - 1) {
463 for (k = i + 1; k < table->num_chunks; ++k)
464 if (table->chunks [k]->num_elements > 0)
467 if (k >= table->num_chunks)
470 g_assert (table->chunks [k]->num_elements > 0);
471 next = table->chunks [k]->data [0];
475 g_assert ((gint8*)this->code_start + this->code_size <= (gint8*)next->code_start + next->code_size);
480 static MonoJitInfoTable*
481 jit_info_table_realloc (MonoJitInfoTable *old)
484 int num_elements = jit_info_table_num_elements (old);
487 int new_chunk, new_element;
488 MonoJitInfoTable *new;
490 /* number of needed places for elements needed */
491 required_size = (int)((long)num_elements * JIT_INFO_TABLE_FILL_RATIO_DENOM / JIT_INFO_TABLE_FILL_RATIO_NOM);
492 num_chunks = (required_size + MONO_JIT_INFO_TABLE_CHUNK_SIZE - 1) / MONO_JIT_INFO_TABLE_CHUNK_SIZE;
493 if (num_chunks == 0) {
494 g_assert (num_elements == 0);
495 return jit_info_table_new (old->domain);
497 g_assert (num_chunks > 0);
499 new = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*) * num_chunks);
500 new->domain = old->domain;
501 new->num_chunks = num_chunks;
503 for (i = 0; i < num_chunks; ++i)
504 new->chunks [i] = jit_info_table_new_chunk ();
508 for (i = 0; i < old->num_chunks; ++i) {
509 MonoJitInfoTableChunk *chunk = old->chunks [i];
510 int chunk_num_elements = chunk->num_elements;
513 for (j = 0; j < chunk_num_elements; ++j) {
514 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j])) {
515 g_assert (new_chunk < num_chunks);
516 new->chunks [new_chunk]->data [new_element] = chunk->data [j];
517 if (++new_element >= JIT_INFO_TABLE_FILLED_NUM_ELEMENTS) {
518 new->chunks [new_chunk]->num_elements = new_element;
526 if (new_chunk < num_chunks) {
527 g_assert (new_chunk == num_chunks - 1);
528 new->chunks [new_chunk]->num_elements = new_element;
529 g_assert (new->chunks [new_chunk]->num_elements > 0);
532 for (i = 0; i < num_chunks; ++i) {
533 MonoJitInfoTableChunk *chunk = new->chunks [i];
534 MonoJitInfo *ji = chunk->data [chunk->num_elements - 1];
536 new->chunks [i]->last_code_end = (gint8*)ji->code_start + ji->code_size;
543 jit_info_table_split_chunk (MonoJitInfoTableChunk *chunk, MonoJitInfoTableChunk **new1p, MonoJitInfoTableChunk **new2p)
545 MonoJitInfoTableChunk *new1 = jit_info_table_new_chunk ();
546 MonoJitInfoTableChunk *new2 = jit_info_table_new_chunk ();
548 g_assert (chunk->num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE);
550 new1->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE / 2;
551 new2->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE - new1->num_elements;
553 memcpy ((void*)new1->data, (void*)chunk->data, sizeof (MonoJitInfo*) * new1->num_elements);
554 memcpy ((void*)new2->data, (void*)(chunk->data + new1->num_elements), sizeof (MonoJitInfo*) * new2->num_elements);
556 new1->last_code_end = (gint8*)new1->data [new1->num_elements - 1]->code_start
557 + new1->data [new1->num_elements - 1]->code_size;
558 new2->last_code_end = (gint8*)new2->data [new2->num_elements - 1]->code_start
559 + new2->data [new2->num_elements - 1]->code_size;
565 static MonoJitInfoTable*
566 jit_info_table_copy_and_split_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
568 MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
569 + sizeof (MonoJitInfoTableChunk*) * (table->num_chunks + 1));
572 new_table->domain = table->domain;
573 new_table->num_chunks = table->num_chunks + 1;
576 for (i = 0; i < table->num_chunks; ++i) {
577 if (table->chunks [i] == chunk) {
578 jit_info_table_split_chunk (chunk, &new_table->chunks [j], &new_table->chunks [j + 1]);
581 new_table->chunks [j] = table->chunks [i];
582 ++new_table->chunks [j]->refcount;
587 g_assert (j == new_table->num_chunks);
592 static MonoJitInfoTableChunk*
593 jit_info_table_purify_chunk (MonoJitInfoTableChunk *old)
595 MonoJitInfoTableChunk *new = jit_info_table_new_chunk ();
599 for (i = 0; i < old->num_elements; ++i) {
600 if (!IS_JIT_INFO_TOMBSTONE (old->data [i]))
601 new->data [j++] = old->data [i];
604 new->num_elements = j;
605 if (new->num_elements > 0)
606 new->last_code_end = (gint8*)new->data [j - 1]->code_start + new->data [j - 1]->code_size;
608 new->last_code_end = old->last_code_end;
613 static MonoJitInfoTable*
614 jit_info_table_copy_and_purify_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
616 MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
617 + sizeof (MonoJitInfoTableChunk*) * table->num_chunks);
620 new_table->domain = table->domain;
621 new_table->num_chunks = table->num_chunks;
624 for (i = 0; i < table->num_chunks; ++i) {
625 if (table->chunks [i] == chunk)
626 new_table->chunks [j++] = jit_info_table_purify_chunk (table->chunks [i]);
628 new_table->chunks [j] = table->chunks [i];
629 ++new_table->chunks [j]->refcount;
634 g_assert (j == new_table->num_chunks);
639 /* As we add an element to the table the case can arise that the chunk
640 * to which we need to add is already full. In that case we have to
641 * allocate a new table and do something about that chunk. We have
642 * several strategies:
644 * If the number of elements in the table is below the low watermark
645 * or above the high watermark, we reallocate the whole table.
646 * Otherwise we only concern ourselves with the overflowing chunk:
648 * If there are no tombstones in the chunk then we split the chunk in
649 * two, each half full.
651 * If the chunk does contain tombstones, we just make a new copy of
652 * the chunk without the tombstones, which will have room for at least
653 * the one element we have to add.
655 static MonoJitInfoTable*
656 jit_info_table_chunk_overflow (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
658 int num_elements = jit_info_table_num_elements (table);
661 if (num_elements < JIT_INFO_TABLE_LOW_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)
662 || num_elements > JIT_INFO_TABLE_HIGH_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)) {
663 //printf ("reallocing table\n");
664 return jit_info_table_realloc (table);
667 /* count the number of non-tombstone elements in the chunk */
669 for (i = 0; i < chunk->num_elements; ++i) {
670 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [i]))
674 if (num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
675 //printf ("splitting chunk\n");
676 return jit_info_table_copy_and_split_chunk (table, chunk);
679 //printf ("purifying chunk\n");
680 return jit_info_table_copy_and_purify_chunk (table, chunk);
683 /* We add elements to the table by first making space for them by
684 * shifting the elements at the back to the right, one at a time.
685 * This results in duplicate entries during the process, but during
686 * all the time the table is in a sorted state. Also, when an element
687 * is replaced by another one, the element that replaces it has an end
688 * address that is equal to or lower than that of the replaced
689 * element. That property is necessary to guarantee that when
690 * searching for an element we end up at a position not higher than
691 * the one we're looking for (i.e. we either find the element directly
692 * or we end up to the left of it).
695 jit_info_table_add (MonoDomain *domain, MonoJitInfoTable *volatile *table_ptr, MonoJitInfo *ji)
697 MonoJitInfoTable *table;
698 MonoJitInfoTableChunk *chunk;
706 chunk_pos = jit_info_table_index (table, (gint8*)ji->code_start + ji->code_size);
707 g_assert (chunk_pos < table->num_chunks);
708 chunk = table->chunks [chunk_pos];
710 if (chunk->num_elements >= MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
711 MonoJitInfoTable *new_table = jit_info_table_chunk_overflow (table, chunk);
713 /* Debugging code, should be removed. */
714 //jit_info_table_check (new_table);
716 *table_ptr = new_table;
717 mono_memory_barrier ();
718 domain->num_jit_info_tables++;
719 mono_thread_hazardous_free_or_queue (table, (MonoHazardousFreeFunc)jit_info_table_free, TRUE, FALSE);
725 /* Debugging code, should be removed. */
726 //jit_info_table_check (table);
728 num_elements = chunk->num_elements;
730 pos = jit_info_table_chunk_index (chunk, NULL, (gint8*)ji->code_start + ji->code_size);
732 /* First we need to size up the chunk by one, by copying the
733 last item, or inserting the first one, if the table is
735 if (num_elements > 0)
736 chunk->data [num_elements] = chunk->data [num_elements - 1];
738 chunk->data [0] = ji;
739 mono_memory_write_barrier ();
740 chunk->num_elements = ++num_elements;
742 /* Shift the elements up one by one. */
743 for (i = num_elements - 2; i >= pos; --i) {
744 mono_memory_write_barrier ();
745 chunk->data [i + 1] = chunk->data [i];
748 /* Now we have room and can insert the new item. */
749 mono_memory_write_barrier ();
750 chunk->data [pos] = ji;
752 /* Set the high code end address chunk entry. */
753 chunk->last_code_end = (gint8*)chunk->data [chunk->num_elements - 1]->code_start
754 + chunk->data [chunk->num_elements - 1]->code_size;
756 /* Debugging code, should be removed. */
757 //jit_info_table_check (table);
761 mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
763 g_assert (ji->d.method != NULL);
765 mono_domain_lock (domain);
767 ++mono_stats.jit_info_table_insert_count;
769 jit_info_table_add (domain, &domain->jit_info_table, ji);
771 mono_domain_unlock (domain);
775 mono_jit_info_make_tombstone (MonoJitInfo *ji)
777 MonoJitInfo *tombstone = g_new0 (MonoJitInfo, 1);
779 tombstone->code_start = ji->code_start;
780 tombstone->code_size = ji->code_size;
781 tombstone->d.method = JIT_INFO_TOMBSTONE_MARKER;
787 * LOCKING: domain lock
790 mono_jit_info_free_or_queue (MonoDomain *domain, MonoJitInfo *ji)
792 if (domain->num_jit_info_tables <= 1) {
793 /* Can it actually happen that we only have one table
794 but ji is still hazardous? */
795 mono_thread_hazardous_free_or_queue (ji, g_free, TRUE, FALSE);
797 domain->jit_info_free_queue = g_slist_prepend (domain->jit_info_free_queue, ji);
802 jit_info_table_remove (MonoJitInfoTable *table, MonoJitInfo *ji)
804 MonoJitInfoTableChunk *chunk;
805 gpointer start = ji->code_start;
808 chunk_pos = jit_info_table_index (table, start);
809 g_assert (chunk_pos < table->num_chunks);
811 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], NULL, start);
814 chunk = table->chunks [chunk_pos];
816 while (pos < chunk->num_elements) {
817 if (chunk->data [pos] == ji)
820 g_assert (IS_JIT_INFO_TOMBSTONE (chunk->data [pos]));
821 g_assert ((guint8*)chunk->data [pos]->code_start + chunk->data [pos]->code_size
822 <= (guint8*)ji->code_start + ji->code_size);
829 } while (chunk_pos < table->num_chunks);
832 g_assert (chunk->data [pos] == ji);
834 chunk->data [pos] = mono_jit_info_make_tombstone (ji);
836 /* Debugging code, should be removed. */
837 //jit_info_table_check (table);
841 mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
843 MonoJitInfoTable *table;
845 mono_domain_lock (domain);
846 table = domain->jit_info_table;
848 ++mono_stats.jit_info_table_remove_count;
850 jit_info_table_remove (table, ji);
852 mono_jit_info_free_or_queue (domain, ji);
854 mono_domain_unlock (domain);
858 mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
862 g_assert (mono_root_domain);
863 mono_domain_lock (mono_root_domain);
866 * We reuse MonoJitInfoTable to store AOT module info,
867 * this gives us async-safe lookup.
869 if (!mono_root_domain->aot_modules) {
870 mono_root_domain->num_jit_info_tables ++;
871 mono_root_domain->aot_modules = jit_info_table_new (mono_root_domain);
874 ji = g_new0 (MonoJitInfo, 1);
876 ji->code_start = start;
877 ji->code_size = (guint8*)end - (guint8*)start;
878 jit_info_table_add (mono_root_domain, &mono_root_domain->aot_modules, ji);
880 mono_domain_unlock (mono_root_domain);
884 mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func)
886 jit_info_find_in_aot_func = func;
890 mono_jit_info_get_code_start (MonoJitInfo* ji)
892 return ji->code_start;
896 mono_jit_info_get_code_size (MonoJitInfo* ji)
898 return ji->code_size;
902 mono_jit_info_get_method (MonoJitInfo* ji)
904 g_assert (!ji->async);
909 jit_info_key_extract (gpointer value)
911 MonoJitInfo *info = (MonoJitInfo*)value;
913 return info->d.method;
917 jit_info_next_value (gpointer value)
919 MonoJitInfo *info = (MonoJitInfo*)value;
921 return (gpointer*)&info->next_jit_code_hash;
925 mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
927 mono_internal_hash_table_init (jit_code_hash,
928 mono_aligned_addr_hash,
929 jit_info_key_extract,
930 jit_info_next_value);
934 mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
936 if (ji->has_generic_jit_info)
937 return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
943 * mono_jit_info_get_generic_sharing_context:
946 * Returns the jit info's generic sharing context, or NULL if it
949 MonoGenericSharingContext*
950 mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
952 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
955 return gi->generic_sharing_context;
961 * mono_jit_info_set_generic_sharing_context:
963 * @gsctx: a generic sharing context
965 * Sets the jit info's generic sharing context. The jit info must
966 * have memory allocated for the context.
969 mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
971 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
975 gi->generic_sharing_context = gsctx;
978 MonoTryBlockHoleTableJitInfo*
979 mono_jit_info_get_try_block_hole_table_info (MonoJitInfo *ji)
981 if (ji->has_try_block_holes) {
982 char *ptr = (char*)&ji->clauses [ji->num_clauses];
983 if (ji->has_generic_jit_info)
984 ptr += sizeof (MonoGenericJitInfo);
985 return (MonoTryBlockHoleTableJitInfo*)ptr;
992 try_block_hole_table_size (MonoJitInfo *ji)
994 MonoTryBlockHoleTableJitInfo *table;
996 table = mono_jit_info_get_try_block_hole_table_info (ji);
998 return sizeof (MonoTryBlockHoleTableJitInfo) + table->num_holes * sizeof (MonoTryBlockHoleJitInfo);
1002 mono_jit_info_get_arch_eh_info (MonoJitInfo *ji)
1004 if (ji->has_arch_eh_info) {
1005 char *ptr = (char*)&ji->clauses [ji->num_clauses];
1006 if (ji->has_generic_jit_info)
1007 ptr += sizeof (MonoGenericJitInfo);
1008 if (ji->has_try_block_holes)
1009 ptr += try_block_hole_table_size (ji);
1010 return (MonoArchEHJitInfo*)ptr;
1017 mono_jit_info_get_cas_info (MonoJitInfo *ji)
1019 if (ji->has_cas_info) {
1020 char *ptr = (char*)&ji->clauses [ji->num_clauses];
1021 if (ji->has_generic_jit_info)
1022 ptr += sizeof (MonoGenericJitInfo);
1023 if (ji->has_try_block_holes)
1024 ptr += try_block_hole_table_size (ji);
1025 if (ji->has_arch_eh_info)
1026 ptr += sizeof (MonoArchEHJitInfo);
1027 return (MonoMethodCasInfo*)ptr;
1033 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
1034 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
1036 static LockFreeMempool*
1037 lock_free_mempool_new (void)
1039 return g_new0 (LockFreeMempool, 1);
1043 lock_free_mempool_free (LockFreeMempool *mp)
1045 LockFreeMempoolChunk *chunk, *next;
1050 mono_vfree (chunk, mono_pagesize ());
1057 * This is async safe
1059 static LockFreeMempoolChunk*
1060 lock_free_mempool_chunk_new (LockFreeMempool *mp, int len)
1062 LockFreeMempoolChunk *chunk, *prev;
1065 size = mono_pagesize ();
1066 while (size - sizeof (LockFreeMempoolChunk) < len)
1067 size += mono_pagesize ();
1068 chunk = mono_valloc (0, size, MONO_MMAP_READ|MONO_MMAP_WRITE);
1070 chunk->mem = ALIGN_PTR_TO ((char*)chunk + sizeof (LockFreeMempoolChunk), 16);
1071 chunk->size = ((char*)chunk + size) - (char*)chunk->mem;
1074 /* Add to list of chunks lock-free */
1077 if (InterlockedCompareExchangePointer ((volatile gpointer*)&mp->chunks, chunk, prev) == prev)
1086 * This is async safe
1089 lock_free_mempool_alloc0 (LockFreeMempool *mp, guint size)
1091 LockFreeMempoolChunk *chunk;
1095 // FIXME: Free the allocator
1097 size = ALIGN_TO (size, 8);
1098 chunk = mp->current;
1100 chunk = lock_free_mempool_chunk_new (mp, size);
1101 mono_memory_barrier ();
1103 mp->current = chunk;
1106 /* The code below is lock-free, 'chunk' is shared state */
1107 oldpos = InterlockedExchangeAdd (&chunk->pos, size);
1108 if (oldpos + size > chunk->size) {
1109 chunk = lock_free_mempool_chunk_new (mp, size);
1110 g_assert (chunk->pos + size <= chunk->size);
1113 mono_memory_barrier ();
1114 mp->current = chunk;
1116 res = (char*)chunk->mem + oldpos;
1123 mono_install_create_domain_hook (MonoCreateDomainFunc func)
1125 create_domain_hook = func;
1129 mono_install_free_domain_hook (MonoFreeDomainFunc func)
1131 free_domain_hook = func;
1135 * mono_string_equal:
1136 * @s1: First string to compare
1137 * @s2: Second string to compare
1139 * Returns FALSE if the strings differ.
1142 mono_string_equal (MonoString *s1, MonoString *s2)
1144 int l1 = mono_string_length (s1);
1145 int l2 = mono_string_length (s2);
1152 return memcmp (mono_string_chars (s1), mono_string_chars (s2), l1 * 2) == 0;
1157 * @s: the string to hash
1159 * Returns the hash for the string.
1162 mono_string_hash (MonoString *s)
1164 const guint16 *p = mono_string_chars (s);
1165 int i, len = mono_string_length (s);
1168 for (i = 0; i < len; i++) {
1169 h = (h << 5) - h + *p;
1177 mono_ptrarray_equal (gpointer *s1, gpointer *s2)
1179 int len = GPOINTER_TO_INT (s1 [0]);
1180 if (len != GPOINTER_TO_INT (s2 [0]))
1183 return memcmp (s1 + 1, s2 + 1, len * sizeof(gpointer)) == 0;
1187 mono_ptrarray_hash (gpointer *s)
1190 int len = GPOINTER_TO_INT (s [0]);
1193 for (i = 1; i < len; i++)
1194 hash += GPOINTER_TO_UINT (s [i]);
1200 * Allocate an id for domain and set domain->domain_id.
1201 * LOCKING: must be called while holding appdomains_mutex.
1202 * We try to assign low numbers to the domain, so it can be used
1203 * as an index in data tables to lookup domain-specific info
1204 * with minimal memory overhead. We also try not to reuse the
1205 * same id too quickly (to help debugging).
1208 domain_id_alloc (MonoDomain *domain)
1211 if (!appdomains_list) {
1212 appdomain_list_size = 2;
1213 appdomains_list = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1215 for (i = appdomain_next; i < appdomain_list_size; ++i) {
1216 if (!appdomains_list [i]) {
1222 for (i = 0; i < appdomain_next; ++i) {
1223 if (!appdomains_list [i]) {
1230 MonoDomain **new_list;
1231 int new_size = appdomain_list_size * 2;
1232 if (new_size >= (1 << 16))
1233 g_assert_not_reached ();
1234 id = appdomain_list_size;
1235 new_list = mono_gc_alloc_fixed (new_size * sizeof (void*), NULL);
1236 memcpy (new_list, appdomains_list, appdomain_list_size * sizeof (void*));
1237 mono_gc_free_fixed (appdomains_list);
1238 appdomains_list = new_list;
1239 appdomain_list_size = new_size;
1241 domain->domain_id = id;
1242 appdomains_list [id] = domain;
1244 if (appdomain_next > appdomain_list_size)
1249 static gsize domain_gc_bitmap [sizeof(MonoDomain)/4/32 + 1];
1250 static gpointer domain_gc_desc = NULL;
1251 static guint32 domain_shadow_serial = 0L;
1254 mono_domain_create (void)
1257 guint32 shadow_serial;
1259 mono_appdomains_lock ();
1260 shadow_serial = domain_shadow_serial++;
1262 if (!domain_gc_desc) {
1263 unsigned int i, bit = 0;
1264 for (i = G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_OBJECT); i < G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_GC_TRACKED); i += sizeof (gpointer)) {
1265 bit = i / sizeof (gpointer);
1266 domain_gc_bitmap [bit / 32] |= (gsize) 1 << (bit % 32);
1268 domain_gc_desc = mono_gc_make_descr_from_bitmap ((gsize*)domain_gc_bitmap, bit + 1);
1270 mono_appdomains_unlock ();
1272 #ifdef HAVE_BOEHM_GC
1274 * Boehm doesn't like roots inside GC allocated objects, and alloc_fixed returns
1275 * a GC_MALLOC-ed object, contrary to the api docs. This causes random crashes when
1276 * running the corlib test suite.
1277 * To solve this, we pass a NULL descriptor, and don't register roots.
1279 domain = mono_gc_alloc_fixed (sizeof (MonoDomain), NULL);
1281 domain = mono_gc_alloc_fixed (sizeof (MonoDomain), domain_gc_desc);
1282 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);
1284 domain->shadow_serial = shadow_serial;
1285 domain->domain = NULL;
1286 domain->setup = NULL;
1287 domain->friendly_name = NULL;
1288 domain->search_path = NULL;
1290 mono_profiler_appdomain_event (domain, MONO_PROFILE_START_LOAD);
1292 domain->mp = mono_mempool_new ();
1293 domain->code_mp = mono_code_manager_new ();
1294 domain->lock_free_mp = lock_free_mempool_new ();
1295 domain->env = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1296 domain->domain_assemblies = NULL;
1297 domain->assembly_bindings = NULL;
1298 domain->assembly_bindings_parsed = FALSE;
1299 domain->class_vtable_array = g_ptr_array_new ();
1300 domain->proxy_vtable_hash = g_hash_table_new ((GHashFunc)mono_ptrarray_hash, (GCompareFunc)mono_ptrarray_equal);
1301 domain->static_data_array = NULL;
1302 mono_jit_code_hash_init (&domain->jit_code_hash);
1303 domain->ldstr_table = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1304 domain->num_jit_info_tables = 1;
1305 domain->jit_info_table = jit_info_table_new (domain);
1306 domain->jit_info_free_queue = NULL;
1307 domain->finalizable_objects_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1308 domain->ftnptrs_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1310 mono_mutex_init_recursive (&domain->lock);
1311 mono_mutex_init_recursive (&domain->assemblies_lock);
1312 mono_mutex_init_recursive (&domain->jit_code_hash_lock);
1313 mono_mutex_init_recursive (&domain->finalizable_objects_hash_lock);
1315 domain->method_rgctx_hash = NULL;
1317 mono_appdomains_lock ();
1318 domain_id_alloc (domain);
1319 mono_appdomains_unlock ();
1321 #ifndef DISABLE_PERFCOUNTERS
1322 mono_perfcounters->loader_appdomains++;
1323 mono_perfcounters->loader_total_appdomains++;
1326 mono_debug_domain_create (domain);
1328 if (create_domain_hook)
1329 create_domain_hook (domain);
1331 mono_profiler_appdomain_loaded (domain, MONO_PROFILE_OK);
1337 * mono_init_internal:
1339 * Creates the initial application domain and initializes the mono_defaults
1341 * This function is guaranteed to not run any IL code.
1342 * If exe_filename is not NULL, the method will determine the required runtime
1343 * from the exe configuration file or the version PE field.
1344 * If runtime_version is not NULL, that runtime version will be used.
1345 * Either exe_filename or runtime_version must be provided.
1347 * Returns: the initial domain.
1350 mono_init_internal (const char *filename, const char *exe_filename, const char *runtime_version)
1352 static MonoDomain *domain = NULL;
1353 MonoAssembly *ass = NULL;
1354 MonoImageOpenStatus status = MONO_IMAGE_OK;
1355 const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
1358 #ifdef DEBUG_DOMAIN_UNLOAD
1359 debug_domain_unload = TRUE;
1363 g_assert_not_reached ();
1366 /* Avoid system error message boxes. */
1367 SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1374 #ifndef DISABLE_PERFCOUNTERS
1375 mono_perfcounters_init ();
1378 mono_counters_register ("Max native code in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_size);
1379 mono_counters_register ("Max code space allocated in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_alloc);
1380 mono_counters_register ("Total code space allocated", MONO_COUNTER_INT|MONO_COUNTER_JIT, &total_domain_code_alloc);
1382 mono_gc_base_init ();
1384 MONO_FAST_TLS_INIT (tls_appdomain);
1385 mono_native_tls_alloc (&appdomain_thread_id, NULL);
1387 mono_mutex_init_recursive (&appdomains_mutex);
1389 mono_metadata_init ();
1390 mono_images_init ();
1391 mono_assemblies_init ();
1392 mono_classes_init ();
1393 mono_loader_init ();
1394 mono_reflection_init ();
1395 mono_runtime_init_tls ();
1397 /* FIXME: When should we release this memory? */
1398 MONO_GC_REGISTER_ROOT_FIXED (appdomains_list);
1400 domain = mono_domain_create ();
1401 mono_root_domain = domain;
1403 SET_APPDOMAIN (domain);
1405 /* Get a list of runtimes supported by the exe */
1406 if (exe_filename != NULL) {
1408 * This function will load the exe file as a MonoImage. We need to close it, but
1409 * that would mean it would be reloaded later. So instead, we save it to
1410 * exe_image, and close it during shutdown.
1412 get_runtimes_from_exe (exe_filename, &exe_image, runtimes);
1415 exe_image = mono_assembly_open_from_bundle (exe_filename, NULL, FALSE);
1417 exe_image = mono_image_open (exe_filename, NULL);
1419 mono_fixup_exe_image (exe_image);
1421 } else if (runtime_version != NULL) {
1422 runtimes [0] = get_runtime_by_version (runtime_version);
1423 runtimes [1] = NULL;
1426 if (runtimes [0] == NULL) {
1427 const MonoRuntimeInfo *default_runtime = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
1428 runtimes [0] = default_runtime;
1429 runtimes [1] = NULL;
1430 g_print ("WARNING: The runtime version supported by this application is unavailable.\n");
1431 g_print ("Using default runtime: %s\n", default_runtime->runtime_version);
1434 /* The selected runtime will be the first one for which there is a mscrolib.dll */
1435 for (n = 0; runtimes [n] != NULL && ass == NULL; n++) {
1436 current_runtime = runtimes [n];
1437 ass = mono_assembly_load_corlib (current_runtime, &status);
1438 if (status != MONO_IMAGE_OK && status != MONO_IMAGE_ERROR_ERRNO)
1443 if ((status != MONO_IMAGE_OK) || (ass == NULL)) {
1445 case MONO_IMAGE_ERROR_ERRNO: {
1446 char *corlib_file = g_build_filename (mono_assembly_getrootdir (), "mono", current_runtime->framework_version, "mscorlib.dll", NULL);
1447 g_print ("The assembly mscorlib.dll was not found or could not be loaded.\n");
1448 g_print ("It should have been installed in the `%s' directory.\n", corlib_file);
1449 g_free (corlib_file);
1452 case MONO_IMAGE_IMAGE_INVALID:
1453 g_print ("The file %s/mscorlib.dll is an invalid CIL image\n",
1454 mono_assembly_getrootdir ());
1456 case MONO_IMAGE_MISSING_ASSEMBLYREF:
1457 g_print ("Missing assembly reference in %s/mscorlib.dll\n",
1458 mono_assembly_getrootdir ());
1461 /* to suppress compiler warning */
1467 mono_defaults.corlib = mono_assembly_get_image (ass);
1469 mono_defaults.object_class = mono_class_from_name (
1470 mono_defaults.corlib, "System", "Object");
1471 g_assert (mono_defaults.object_class != 0);
1473 mono_defaults.void_class = mono_class_from_name (
1474 mono_defaults.corlib, "System", "Void");
1475 g_assert (mono_defaults.void_class != 0);
1477 mono_defaults.boolean_class = mono_class_from_name (
1478 mono_defaults.corlib, "System", "Boolean");
1479 g_assert (mono_defaults.boolean_class != 0);
1481 mono_defaults.byte_class = mono_class_from_name (
1482 mono_defaults.corlib, "System", "Byte");
1483 g_assert (mono_defaults.byte_class != 0);
1485 mono_defaults.sbyte_class = mono_class_from_name (
1486 mono_defaults.corlib, "System", "SByte");
1487 g_assert (mono_defaults.sbyte_class != 0);
1489 mono_defaults.int16_class = mono_class_from_name (
1490 mono_defaults.corlib, "System", "Int16");
1491 g_assert (mono_defaults.int16_class != 0);
1493 mono_defaults.uint16_class = mono_class_from_name (
1494 mono_defaults.corlib, "System", "UInt16");
1495 g_assert (mono_defaults.uint16_class != 0);
1497 mono_defaults.int32_class = mono_class_from_name (
1498 mono_defaults.corlib, "System", "Int32");
1499 g_assert (mono_defaults.int32_class != 0);
1501 mono_defaults.uint32_class = mono_class_from_name (
1502 mono_defaults.corlib, "System", "UInt32");
1503 g_assert (mono_defaults.uint32_class != 0);
1505 mono_defaults.uint_class = mono_class_from_name (
1506 mono_defaults.corlib, "System", "UIntPtr");
1507 g_assert (mono_defaults.uint_class != 0);
1509 mono_defaults.int_class = mono_class_from_name (
1510 mono_defaults.corlib, "System", "IntPtr");
1511 g_assert (mono_defaults.int_class != 0);
1513 mono_defaults.int64_class = mono_class_from_name (
1514 mono_defaults.corlib, "System", "Int64");
1515 g_assert (mono_defaults.int64_class != 0);
1517 mono_defaults.uint64_class = mono_class_from_name (
1518 mono_defaults.corlib, "System", "UInt64");
1519 g_assert (mono_defaults.uint64_class != 0);
1521 mono_defaults.single_class = mono_class_from_name (
1522 mono_defaults.corlib, "System", "Single");
1523 g_assert (mono_defaults.single_class != 0);
1525 mono_defaults.double_class = mono_class_from_name (
1526 mono_defaults.corlib, "System", "Double");
1527 g_assert (mono_defaults.double_class != 0);
1529 mono_defaults.char_class = mono_class_from_name (
1530 mono_defaults.corlib, "System", "Char");
1531 g_assert (mono_defaults.char_class != 0);
1533 mono_defaults.string_class = mono_class_from_name (
1534 mono_defaults.corlib, "System", "String");
1535 g_assert (mono_defaults.string_class != 0);
1537 mono_defaults.enum_class = mono_class_from_name (
1538 mono_defaults.corlib, "System", "Enum");
1539 g_assert (mono_defaults.enum_class != 0);
1541 mono_defaults.array_class = mono_class_from_name (
1542 mono_defaults.corlib, "System", "Array");
1543 g_assert (mono_defaults.array_class != 0);
1545 mono_defaults.delegate_class = mono_class_from_name (
1546 mono_defaults.corlib, "System", "Delegate");
1547 g_assert (mono_defaults.delegate_class != 0 );
1549 mono_defaults.multicastdelegate_class = mono_class_from_name (
1550 mono_defaults.corlib, "System", "MulticastDelegate");
1551 g_assert (mono_defaults.multicastdelegate_class != 0 );
1553 mono_defaults.asyncresult_class = mono_class_from_name (
1554 mono_defaults.corlib, "System.Runtime.Remoting.Messaging",
1556 g_assert (mono_defaults.asyncresult_class != 0 );
1558 mono_defaults.manualresetevent_class = mono_class_from_name (
1559 mono_defaults.corlib, "System.Threading", "ManualResetEvent");
1560 g_assert (mono_defaults.manualresetevent_class != 0 );
1562 mono_defaults.typehandle_class = mono_class_from_name (
1563 mono_defaults.corlib, "System", "RuntimeTypeHandle");
1564 g_assert (mono_defaults.typehandle_class != 0);
1566 mono_defaults.methodhandle_class = mono_class_from_name (
1567 mono_defaults.corlib, "System", "RuntimeMethodHandle");
1568 g_assert (mono_defaults.methodhandle_class != 0);
1570 mono_defaults.fieldhandle_class = mono_class_from_name (
1571 mono_defaults.corlib, "System", "RuntimeFieldHandle");
1572 g_assert (mono_defaults.fieldhandle_class != 0);
1574 mono_defaults.systemtype_class = mono_class_from_name (
1575 mono_defaults.corlib, "System", "Type");
1576 g_assert (mono_defaults.systemtype_class != 0);
1578 mono_defaults.monotype_class = mono_class_from_name (
1579 mono_defaults.corlib, "System", "MonoType");
1580 g_assert (mono_defaults.monotype_class != 0);
1582 mono_defaults.exception_class = mono_class_from_name (
1583 mono_defaults.corlib, "System", "Exception");
1584 g_assert (mono_defaults.exception_class != 0);
1586 mono_defaults.threadabortexception_class = mono_class_from_name (
1587 mono_defaults.corlib, "System.Threading", "ThreadAbortException");
1588 g_assert (mono_defaults.threadabortexception_class != 0);
1590 mono_defaults.thread_class = mono_class_from_name (
1591 mono_defaults.corlib, "System.Threading", "Thread");
1592 g_assert (mono_defaults.thread_class != 0);
1594 mono_defaults.internal_thread_class = mono_class_from_name (
1595 mono_defaults.corlib, "System.Threading", "InternalThread");
1596 if (!mono_defaults.internal_thread_class) {
1597 /* This can happen with an old mscorlib */
1598 fprintf (stderr, "Corlib too old for this runtime.\n");
1599 fprintf (stderr, "Loaded from: %s\n",
1600 mono_defaults.corlib? mono_image_get_filename (mono_defaults.corlib): "unknown");
1604 mono_defaults.appdomain_class = mono_class_from_name (
1605 mono_defaults.corlib, "System", "AppDomain");
1606 g_assert (mono_defaults.appdomain_class != 0);
1608 #ifndef DISABLE_REMOTING
1609 mono_defaults.transparent_proxy_class = mono_class_from_name (
1610 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "TransparentProxy");
1611 g_assert (mono_defaults.transparent_proxy_class != 0);
1613 mono_defaults.real_proxy_class = mono_class_from_name (
1614 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "RealProxy");
1615 g_assert (mono_defaults.real_proxy_class != 0);
1617 mono_defaults.marshalbyrefobject_class = mono_class_from_name (
1618 mono_defaults.corlib, "System", "MarshalByRefObject");
1619 g_assert (mono_defaults.marshalbyrefobject_class != 0);
1621 mono_defaults.iremotingtypeinfo_class = mono_class_from_name (
1622 mono_defaults.corlib, "System.Runtime.Remoting", "IRemotingTypeInfo");
1623 g_assert (mono_defaults.iremotingtypeinfo_class != 0);
1626 mono_defaults.mono_method_message_class = mono_class_from_name (
1627 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", "MonoMethodMessage");
1628 g_assert (mono_defaults.mono_method_message_class != 0);
1630 mono_defaults.field_info_class = mono_class_from_name (
1631 mono_defaults.corlib, "System.Reflection", "FieldInfo");
1632 g_assert (mono_defaults.field_info_class != 0);
1634 mono_defaults.method_info_class = mono_class_from_name (
1635 mono_defaults.corlib, "System.Reflection", "MethodInfo");
1636 g_assert (mono_defaults.method_info_class != 0);
1638 mono_defaults.stringbuilder_class = mono_class_from_name (
1639 mono_defaults.corlib, "System.Text", "StringBuilder");
1640 g_assert (mono_defaults.stringbuilder_class != 0);
1642 mono_defaults.math_class = mono_class_from_name (
1643 mono_defaults.corlib, "System", "Math");
1644 g_assert (mono_defaults.math_class != 0);
1646 mono_defaults.stack_frame_class = mono_class_from_name (
1647 mono_defaults.corlib, "System.Diagnostics", "StackFrame");
1648 g_assert (mono_defaults.stack_frame_class != 0);
1650 mono_defaults.stack_trace_class = mono_class_from_name (
1651 mono_defaults.corlib, "System.Diagnostics", "StackTrace");
1652 g_assert (mono_defaults.stack_trace_class != 0);
1654 mono_defaults.marshal_class = mono_class_from_name (
1655 mono_defaults.corlib, "System.Runtime.InteropServices", "Marshal");
1656 g_assert (mono_defaults.marshal_class != 0);
1658 mono_defaults.typed_reference_class = mono_class_from_name (
1659 mono_defaults.corlib, "System", "TypedReference");
1660 g_assert (mono_defaults.typed_reference_class != 0);
1662 mono_defaults.argumenthandle_class = mono_class_from_name (
1663 mono_defaults.corlib, "System", "RuntimeArgumentHandle");
1664 g_assert (mono_defaults.argumenthandle_class != 0);
1666 mono_defaults.monitor_class = mono_class_from_name (
1667 mono_defaults.corlib, "System.Threading", "Monitor");
1668 g_assert (mono_defaults.monitor_class != 0);
1670 mono_defaults.runtimesecurityframe_class = mono_class_from_name (
1671 mono_defaults.corlib, "System.Security", "RuntimeSecurityFrame");
1673 mono_defaults.executioncontext_class = mono_class_from_name (
1674 mono_defaults.corlib, "System.Threading", "ExecutionContext");
1676 mono_defaults.internals_visible_class = mono_class_from_name (
1677 mono_defaults.corlib, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute");
1679 mono_defaults.critical_finalizer_object = mono_class_from_name (
1680 mono_defaults.corlib, "System.Runtime.ConstrainedExecution", "CriticalFinalizerObject");
1683 * mscorlib needs a little help, only now it can load its friends list (after we have
1684 * loaded the InternalsVisibleToAttribute), load it now
1686 mono_assembly_load_friends (ass);
1688 mono_defaults.safehandle_class = mono_class_from_name (
1689 mono_defaults.corlib, "System.Runtime.InteropServices", "SafeHandle");
1691 mono_defaults.handleref_class = mono_class_from_name (
1692 mono_defaults.corlib, "System.Runtime.InteropServices", "HandleRef");
1694 mono_defaults.attribute_class = mono_class_from_name (
1695 mono_defaults.corlib, "System", "Attribute");
1697 mono_defaults.customattribute_data_class = mono_class_from_name (
1698 mono_defaults.corlib, "System.Reflection", "CustomAttributeData");
1700 /* these are initialized lazily when COM features are used */
1702 mono_class_init (mono_defaults.array_class);
1703 mono_defaults.generic_nullable_class = mono_class_from_name (
1704 mono_defaults.corlib, "System", "Nullable`1");
1705 mono_defaults.generic_ilist_class = mono_class_from_name (
1706 mono_defaults.corlib, "System.Collections.Generic", "IList`1");
1707 mono_defaults.generic_ireadonlylist_class = mono_class_from_name (
1708 mono_defaults.corlib, "System.Collections.Generic", "IReadOnlyList`1");
1710 domain->friendly_name = g_path_get_basename (filename);
1712 _mono_debug_init_corlib (domain);
1720 * Creates the initial application domain and initializes the mono_defaults
1722 * This function is guaranteed to not run any IL code.
1723 * The runtime is initialized using the default runtime version.
1725 * Returns: the initial domain.
1728 mono_init (const char *domain_name)
1730 return mono_init_internal (domain_name, NULL, DEFAULT_RUNTIME_VERSION);
1734 * mono_init_from_assembly:
1735 * @domain_name: name to give to the initial domain
1736 * @filename: filename to load on startup
1738 * Used by the runtime, users should use mono_jit_init instead.
1740 * Creates the initial application domain and initializes the mono_defaults
1742 * This function is guaranteed to not run any IL code.
1743 * The runtime is initialized using the runtime version required by the
1744 * provided executable. The version is determined by looking at the exe
1745 * configuration file and the version PE field)
1747 * Returns: the initial domain.
1750 mono_init_from_assembly (const char *domain_name, const char *filename)
1752 return mono_init_internal (domain_name, filename, NULL);
1756 * mono_init_version:
1758 * Used by the runtime, users should use mono_jit_init instead.
1760 * Creates the initial application domain and initializes the mono_defaults
1763 * This function is guaranteed to not run any IL code.
1764 * The runtime is initialized using the provided rutime version.
1766 * Returns: the initial domain.
1769 mono_init_version (const char *domain_name, const char *version)
1771 return mono_init_internal (domain_name, NULL, version);
1777 * Cleans up all metadata modules.
1782 mono_close_exe_image ();
1784 mono_defaults.corlib = NULL;
1786 mono_config_cleanup ();
1787 mono_loader_cleanup ();
1788 mono_classes_cleanup ();
1789 mono_assemblies_cleanup ();
1790 mono_images_cleanup ();
1791 mono_debug_cleanup ();
1792 mono_metadata_cleanup ();
1794 mono_native_tls_free (appdomain_thread_id);
1795 mono_mutex_destroy (&appdomains_mutex);
1803 mono_close_exe_image (void)
1806 mono_image_close (exe_image);
1810 * mono_get_root_domain:
1812 * The root AppDomain is the initial domain created by the runtime when it is
1813 * initialized. Programs execute on this AppDomain, but can create new ones
1814 * later. Currently there is no unmanaged API to create new AppDomains, this
1815 * must be done from managed code.
1817 * Returns: the root appdomain, to obtain the current domain, use mono_domain_get ()
1820 mono_get_root_domain (void)
1822 return mono_root_domain;
1828 * Returns: the current domain, to obtain the root domain use
1829 * mono_get_root_domain().
1834 return GET_APPDOMAIN ();
1838 mono_domain_unset (void)
1840 SET_APPDOMAIN (NULL);
1844 mono_domain_set_internal_with_options (MonoDomain *domain, gboolean migrate_exception)
1846 MonoInternalThread *thread;
1848 if (mono_domain_get () == domain)
1851 SET_APPDOMAIN (domain);
1852 SET_APPCONTEXT (domain->default_context);
1854 if (migrate_exception) {
1855 thread = mono_thread_internal_current ();
1856 if (!thread->abort_exc)
1859 g_assert (thread->abort_exc->object.vtable->domain != domain);
1860 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
1861 g_assert (thread->abort_exc->object.vtable->domain == domain);
1866 * mono_domain_set_internal:
1867 * @domain: the new domain
1869 * Sets the current domain to @domain.
1872 mono_domain_set_internal (MonoDomain *domain)
1874 mono_domain_set_internal_with_options (domain, TRUE);
1878 mono_domain_foreach (MonoDomainFunc func, gpointer user_data)
1884 * Create a copy of the data to avoid calling the user callback
1885 * inside the lock because that could lead to deadlocks.
1886 * We can do this because this function is not perf. critical.
1888 mono_appdomains_lock ();
1889 size = appdomain_list_size;
1890 copy = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1891 memcpy (copy, appdomains_list, appdomain_list_size * sizeof (void*));
1892 mono_appdomains_unlock ();
1894 for (i = 0; i < size; ++i) {
1896 func (copy [i], user_data);
1899 mono_gc_free_fixed (copy);
1903 * mono_domain_assembly_open:
1904 * @domain: the application domain
1905 * @name: file name of the assembly
1907 * fixme: maybe we should integrate this with mono_assembly_open ??
1910 mono_domain_assembly_open (MonoDomain *domain, const char *name)
1912 MonoDomain *current;
1916 mono_domain_assemblies_lock (domain);
1917 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1919 if (strcmp (name, ass->aname.name) == 0) {
1920 mono_domain_assemblies_unlock (domain);
1924 mono_domain_assemblies_unlock (domain);
1926 if (domain != mono_domain_get ()) {
1927 current = mono_domain_get ();
1929 mono_domain_set (domain, FALSE);
1930 ass = mono_assembly_open (name, NULL);
1931 mono_domain_set (current, FALSE);
1933 ass = mono_assembly_open (name, NULL);
1940 unregister_vtable_reflection_type (MonoVTable *vtable)
1942 MonoObject *type = vtable->type;
1944 if (type->vtable->klass != mono_defaults.monotype_class)
1945 MONO_GC_UNREGISTER_ROOT_IF_MOVING (vtable->type);
1949 mono_domain_free (MonoDomain *domain, gboolean force)
1951 int code_size, code_alloc;
1955 if ((domain == mono_root_domain) && !force) {
1956 g_warning ("cant unload root domain");
1960 if (mono_dont_free_domains)
1963 mono_profiler_appdomain_event (domain, MONO_PROFILE_START_UNLOAD);
1965 mono_debug_domain_unload (domain);
1967 mono_appdomains_lock ();
1968 appdomains_list [domain->domain_id] = NULL;
1969 mono_appdomains_unlock ();
1971 /* must do this early as it accesses fields and types */
1972 if (domain->special_static_fields) {
1973 mono_alloc_special_static_data_free (domain->special_static_fields);
1974 g_hash_table_destroy (domain->special_static_fields);
1975 domain->special_static_fields = NULL;
1979 * We must destroy all these hash tables here because they
1980 * contain references to managed objects belonging to the
1981 * domain. Once we let the GC clear the domain there must be
1982 * no more such references, or we'll crash if a collection
1985 mono_g_hash_table_destroy (domain->ldstr_table);
1986 domain->ldstr_table = NULL;
1988 mono_g_hash_table_destroy (domain->env);
1991 if (domain->tlsrec_list) {
1992 mono_thread_destroy_domain_tls (domain);
1993 domain->tlsrec_list = NULL;
1996 mono_reflection_cleanup_domain (domain);
1998 /* This must be done before type_hash is freed */
1999 if (domain->class_vtable_array) {
2001 for (i = 0; i < domain->class_vtable_array->len; ++i)
2002 unregister_vtable_reflection_type (g_ptr_array_index (domain->class_vtable_array, i));
2005 if (domain->type_hash) {
2006 mono_g_hash_table_destroy (domain->type_hash);
2007 domain->type_hash = NULL;
2009 if (domain->type_init_exception_hash) {
2010 mono_g_hash_table_destroy (domain->type_init_exception_hash);
2011 domain->type_init_exception_hash = NULL;
2014 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2015 MonoAssembly *ass = tmp->data;
2016 mono_assembly_release_gc_roots (ass);
2019 /* Have to zero out reference fields since they will be invalidated by the clear_domain () call below */
2020 for (p = (gpointer*)&domain->MONO_DOMAIN_FIRST_OBJECT; p < (gpointer*)&domain->MONO_DOMAIN_FIRST_GC_TRACKED; ++p)
2023 /* This needs to be done before closing assemblies */
2024 mono_gc_clear_domain (domain);
2026 /* Close dynamic assemblies first, since they have no ref count */
2027 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2028 MonoAssembly *ass = tmp->data;
2029 if (!ass->image || !image_is_dynamic (ass->image))
2031 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);
2032 if (!mono_assembly_close_except_image_pools (ass))
2036 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2037 MonoAssembly *ass = tmp->data;
2040 if (!ass->image || image_is_dynamic (ass->image))
2042 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);
2043 if (!mono_assembly_close_except_image_pools (ass))
2047 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2048 MonoAssembly *ass = tmp->data;
2050 mono_assembly_close_finish (ass);
2052 g_slist_free (domain->domain_assemblies);
2053 domain->domain_assemblies = NULL;
2056 * Send this after the assemblies have been unloaded and the domain is still in a
2059 mono_profiler_appdomain_event (domain, MONO_PROFILE_END_UNLOAD);
2061 if (free_domain_hook)
2062 free_domain_hook (domain);
2064 /* FIXME: free delegate_hash_table when it's used */
2065 if (domain->search_path) {
2066 g_strfreev (domain->search_path);
2067 domain->search_path = NULL;
2069 domain->create_proxy_for_type_method = NULL;
2070 domain->private_invoke_method = NULL;
2071 domain->default_context = NULL;
2072 domain->out_of_memory_ex = NULL;
2073 domain->null_reference_ex = NULL;
2074 domain->stack_overflow_ex = NULL;
2075 domain->ephemeron_tombstone = NULL;
2076 domain->entry_assembly = NULL;
2078 g_free (domain->friendly_name);
2079 domain->friendly_name = NULL;
2080 g_ptr_array_free (domain->class_vtable_array, TRUE);
2081 domain->class_vtable_array = NULL;
2082 g_hash_table_destroy (domain->proxy_vtable_hash);
2083 domain->proxy_vtable_hash = NULL;
2084 if (domain->static_data_array) {
2085 mono_gc_free_fixed (domain->static_data_array);
2086 domain->static_data_array = NULL;
2088 mono_internal_hash_table_destroy (&domain->jit_code_hash);
2091 * There might still be jit info tables of this domain which
2092 * are not freed. Since the domain cannot be in use anymore,
2093 * this will free them.
2095 mono_thread_hazardous_try_free_all ();
2096 if (domain->aot_modules)
2097 jit_info_table_free (domain->aot_modules);
2098 g_assert (domain->num_jit_info_tables == 1);
2099 jit_info_table_free (domain->jit_info_table);
2100 domain->jit_info_table = NULL;
2101 g_assert (!domain->jit_info_free_queue);
2103 /* collect statistics */
2104 code_alloc = mono_code_manager_size (domain->code_mp, &code_size);
2105 total_domain_code_alloc += code_alloc;
2106 max_domain_code_alloc = MAX (max_domain_code_alloc, code_alloc);
2107 max_domain_code_size = MAX (max_domain_code_size, code_size);
2109 if (debug_domain_unload) {
2110 mono_mempool_invalidate (domain->mp);
2111 mono_code_manager_invalidate (domain->code_mp);
2113 #ifndef DISABLE_PERFCOUNTERS
2114 mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (domain->mp);
2116 mono_mempool_destroy (domain->mp);
2118 mono_code_manager_destroy (domain->code_mp);
2119 domain->code_mp = NULL;
2121 lock_free_mempool_free (domain->lock_free_mp);
2122 domain->lock_free_mp = NULL;
2124 g_hash_table_destroy (domain->finalizable_objects_hash);
2125 domain->finalizable_objects_hash = NULL;
2126 if (domain->method_rgctx_hash) {
2127 g_hash_table_destroy (domain->method_rgctx_hash);
2128 domain->method_rgctx_hash = NULL;
2130 if (domain->generic_virtual_cases) {
2131 g_hash_table_destroy (domain->generic_virtual_cases);
2132 domain->generic_virtual_cases = NULL;
2134 if (domain->generic_virtual_thunks) {
2135 g_hash_table_destroy (domain->generic_virtual_thunks);
2136 domain->generic_virtual_thunks = NULL;
2138 if (domain->ftnptrs_hash) {
2139 g_hash_table_destroy (domain->ftnptrs_hash);
2140 domain->ftnptrs_hash = NULL;
2143 mono_mutex_destroy (&domain->finalizable_objects_hash_lock);
2144 mono_mutex_destroy (&domain->assemblies_lock);
2145 mono_mutex_destroy (&domain->jit_code_hash_lock);
2146 mono_mutex_destroy (&domain->lock);
2147 domain->setup = NULL;
2149 mono_gc_deregister_root ((char*)&(domain->MONO_DOMAIN_FIRST_GC_TRACKED));
2151 /* FIXME: anything else required ? */
2153 mono_gc_free_fixed (domain);
2155 #ifndef DISABLE_PERFCOUNTERS
2156 mono_perfcounters->loader_appdomains--;
2159 if (domain == mono_root_domain)
2160 mono_root_domain = NULL;
2164 * mono_domain_get_id:
2167 * Returns: the a domain for a specific domain id.
2170 mono_domain_get_by_id (gint32 domainid)
2172 MonoDomain * domain;
2174 mono_appdomains_lock ();
2175 if (domainid < appdomain_list_size)
2176 domain = appdomains_list [domainid];
2179 mono_appdomains_unlock ();
2185 mono_domain_get_id (MonoDomain *domain)
2187 return domain->domain_id;
2191 * mono_domain_alloc:
2193 * LOCKING: Acquires the domain lock.
2196 mono_domain_alloc (MonoDomain *domain, guint size)
2200 mono_domain_lock (domain);
2201 #ifndef DISABLE_PERFCOUNTERS
2202 mono_perfcounters->loader_bytes += size;
2204 res = mono_mempool_alloc (domain->mp, size);
2205 mono_domain_unlock (domain);
2211 * mono_domain_alloc0:
2213 * LOCKING: Acquires the domain lock.
2216 mono_domain_alloc0 (MonoDomain *domain, guint size)
2220 mono_domain_lock (domain);
2221 #ifndef DISABLE_PERFCOUNTERS
2222 mono_perfcounters->loader_bytes += size;
2224 res = mono_mempool_alloc0 (domain->mp, size);
2225 mono_domain_unlock (domain);
2231 mono_domain_alloc0_lock_free (MonoDomain *domain, guint size)
2233 return lock_free_mempool_alloc0 (domain->lock_free_mp, size);
2237 * mono_domain_code_reserve:
2239 * LOCKING: Acquires the domain lock.
2242 mono_domain_code_reserve (MonoDomain *domain, int size)
2246 mono_domain_lock (domain);
2247 res = mono_code_manager_reserve (domain->code_mp, size);
2248 mono_domain_unlock (domain);
2254 * mono_domain_code_reserve_align:
2256 * LOCKING: Acquires the domain lock.
2259 mono_domain_code_reserve_align (MonoDomain *domain, int size, int alignment)
2263 mono_domain_lock (domain);
2264 res = mono_code_manager_reserve_align (domain->code_mp, size, alignment);
2265 mono_domain_unlock (domain);
2271 * mono_domain_code_commit:
2273 * LOCKING: Acquires the domain lock.
2276 mono_domain_code_commit (MonoDomain *domain, void *data, int size, int newsize)
2278 mono_domain_lock (domain);
2279 mono_code_manager_commit (domain->code_mp, data, size, newsize);
2280 mono_domain_unlock (domain);
2283 #if defined(__native_client_codegen__) && defined(__native_client__)
2285 * Given the temporary buffer (allocated by mono_domain_code_reserve) into which
2286 * we are generating code, return a pointer to the destination in the dynamic
2287 * code segment into which the code will be copied when mono_domain_code_commit
2289 * LOCKING: Acquires the domain lock.
2292 nacl_domain_get_code_dest (MonoDomain *domain, void *data)
2295 mono_domain_lock (domain);
2296 dest = nacl_code_manager_get_code_dest (domain->code_mp, data);
2297 mono_domain_unlock (domain);
2302 * Convenience function which calls mono_domain_code_commit to validate and copy
2303 * the code. The caller sets *buf_base and *buf_size to the start and size of
2304 * the buffer (allocated by mono_domain_code_reserve), and *code_end to the byte
2305 * after the last instruction byte. On return, *buf_base will point to the start
2306 * of the copied in the code segment, and *code_end will point after the end of
2310 nacl_domain_code_validate (MonoDomain *domain, guint8 **buf_base, int buf_size, guint8 **code_end)
2312 guint8 *tmp = nacl_domain_get_code_dest (domain, *buf_base);
2313 mono_domain_code_commit (domain, *buf_base, buf_size, *code_end - *buf_base);
2314 *code_end = tmp + (*code_end - *buf_base);
2320 /* no-op versions of Native Client functions */
2323 nacl_domain_get_code_dest (MonoDomain *domain, void *data)
2329 nacl_domain_code_validate (MonoDomain *domain, guint8 **buf_base, int buf_size, guint8 **code_end)
2336 * mono_domain_code_foreach:
2337 * Iterate over the code thunks of the code manager of @domain.
2339 * The @func callback MUST not take any locks. If it really needs to, it must respect
2340 * the locking rules of the runtime: http://www.mono-project.com/Mono:Runtime:Documentation:ThreadSafety
2341 * LOCKING: Acquires the domain lock.
2345 mono_domain_code_foreach (MonoDomain *domain, MonoCodeManagerFunc func, void *user_data)
2347 mono_domain_lock (domain);
2348 mono_code_manager_foreach (domain->code_mp, func, user_data);
2349 mono_domain_unlock (domain);
2354 mono_context_set (MonoAppContext * new_context)
2356 SET_APPCONTEXT (new_context);
2360 mono_context_get (void)
2362 return GET_APPCONTEXT ();
2365 /* LOCKING: the caller holds the lock for this domain */
2367 mono_domain_add_class_static_data (MonoDomain *domain, MonoClass *klass, gpointer data, guint32 *bitmap)
2369 /* The first entry in the array is the index of the next free slot
2370 * and the total size of the array
2373 if (domain->static_data_array) {
2374 int size = GPOINTER_TO_INT (domain->static_data_array [1]);
2375 next = GPOINTER_TO_INT (domain->static_data_array [0]);
2377 /* 'data' is allocated by alloc_fixed */
2378 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * (size * 2), MONO_GC_ROOT_DESCR_FOR_FIXED (size * 2));
2379 mono_gc_memmove_aligned (new_array, domain->static_data_array, sizeof (gpointer) * size);
2381 new_array [1] = GINT_TO_POINTER (size);
2382 mono_gc_free_fixed (domain->static_data_array);
2383 domain->static_data_array = new_array;
2387 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * size, MONO_GC_ROOT_DESCR_FOR_FIXED (size));
2389 new_array [0] = GINT_TO_POINTER (next);
2390 new_array [1] = GINT_TO_POINTER (size);
2391 domain->static_data_array = new_array;
2393 domain->static_data_array [next++] = data;
2394 domain->static_data_array [0] = GINT_TO_POINTER (next);
2398 mono_get_corlib (void)
2400 return mono_defaults.corlib;
2404 mono_get_object_class (void)
2406 return mono_defaults.object_class;
2410 mono_get_byte_class (void)
2412 return mono_defaults.byte_class;
2416 mono_get_void_class (void)
2418 return mono_defaults.void_class;
2422 mono_get_boolean_class (void)
2424 return mono_defaults.boolean_class;
2428 mono_get_sbyte_class (void)
2430 return mono_defaults.sbyte_class;
2434 mono_get_int16_class (void)
2436 return mono_defaults.int16_class;
2440 mono_get_uint16_class (void)
2442 return mono_defaults.uint16_class;
2446 mono_get_int32_class (void)
2448 return mono_defaults.int32_class;
2452 mono_get_uint32_class (void)
2454 return mono_defaults.uint32_class;
2458 mono_get_intptr_class (void)
2460 return mono_defaults.int_class;
2464 mono_get_uintptr_class (void)
2466 return mono_defaults.uint_class;
2470 mono_get_int64_class (void)
2472 return mono_defaults.int64_class;
2476 mono_get_uint64_class (void)
2478 return mono_defaults.uint64_class;
2482 mono_get_single_class (void)
2484 return mono_defaults.single_class;
2488 mono_get_double_class (void)
2490 return mono_defaults.double_class;
2494 mono_get_char_class (void)
2496 return mono_defaults.char_class;
2500 mono_get_string_class (void)
2502 return mono_defaults.string_class;
2506 mono_get_enum_class (void)
2508 return mono_defaults.enum_class;
2512 mono_get_array_class (void)
2514 return mono_defaults.array_class;
2518 mono_get_thread_class (void)
2520 return mono_defaults.thread_class;
2524 mono_get_exception_class (void)
2526 return mono_defaults.exception_class;
2530 static char* get_attribute_value (const gchar **attribute_names,
2531 const gchar **attribute_values,
2532 const char *att_name)
2535 for (n=0; attribute_names[n] != NULL; n++) {
2536 if (strcmp (attribute_names[n], att_name) == 0)
2537 return g_strdup (attribute_values[n]);
2542 static void start_element (GMarkupParseContext *context,
2543 const gchar *element_name,
2544 const gchar **attribute_names,
2545 const gchar **attribute_values,
2549 AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2551 if (strcmp (element_name, "configuration") == 0) {
2552 app_config->configuration_count++;
2555 if (strcmp (element_name, "startup") == 0) {
2556 app_config->startup_count++;
2560 if (app_config->configuration_count != 1 || app_config->startup_count != 1)
2563 if (strcmp (element_name, "requiredRuntime") == 0) {
2564 app_config->required_runtime = get_attribute_value (attribute_names, attribute_values, "version");
2565 } else if (strcmp (element_name, "supportedRuntime") == 0) {
2566 char *version = get_attribute_value (attribute_names, attribute_values, "version");
2567 app_config->supported_runtimes = g_slist_append (app_config->supported_runtimes, version);
2571 static void end_element (GMarkupParseContext *context,
2572 const gchar *element_name,
2576 AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2578 if (strcmp (element_name, "configuration") == 0) {
2579 app_config->configuration_count--;
2580 } else if (strcmp (element_name, "startup") == 0) {
2581 app_config->startup_count--;
2585 static const GMarkupParser
2594 static AppConfigInfo *
2595 app_config_parse (const char *exe_filename)
2597 AppConfigInfo *app_config;
2598 GMarkupParseContext *context;
2601 const char *bundled_config;
2602 char *config_filename;
2604 bundled_config = mono_config_string_for_assembly_file (exe_filename);
2606 if (bundled_config) {
2607 text = g_strdup (bundled_config);
2608 len = strlen (text);
2610 config_filename = g_strconcat (exe_filename, ".config", NULL);
2612 if (!g_file_get_contents (config_filename, &text, &len, NULL)) {
2613 g_free (config_filename);
2616 g_free (config_filename);
2619 app_config = g_new0 (AppConfigInfo, 1);
2621 context = g_markup_parse_context_new (&mono_parser, 0, app_config, NULL);
2622 if (g_markup_parse_context_parse (context, text, len, NULL)) {
2623 g_markup_parse_context_end_parse (context, NULL);
2625 g_markup_parse_context_free (context);
2631 app_config_free (AppConfigInfo* app_config)
2634 GSList *list = app_config->supported_runtimes;
2635 while (list != NULL) {
2636 rt = (char*)list->data;
2638 list = g_slist_next (list);
2640 g_slist_free (app_config->supported_runtimes);
2641 g_free (app_config->required_runtime);
2642 g_free (app_config);
2646 static const MonoRuntimeInfo*
2647 get_runtime_by_version (const char *version)
2650 int max = G_N_ELEMENTS (supported_runtimes);
2656 for (n=0; n<max; n++) {
2657 if (strcmp (version, supported_runtimes[n].runtime_version) == 0)
2658 return &supported_runtimes[n];
2661 vlen = strlen (version);
2662 if (vlen >= 4 && version [1] - '0' >= 4) {
2663 for (n=0; n<max; n++) {
2664 if (strncmp (version, supported_runtimes[n].runtime_version, 4) == 0)
2665 return &supported_runtimes[n];
2673 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes)
2675 AppConfigInfo* app_config;
2677 const MonoRuntimeInfo* runtime = NULL;
2678 MonoImage *image = NULL;
2680 app_config = app_config_parse (exe_file);
2682 if (app_config != NULL) {
2683 /* Check supportedRuntime elements, if none is supported, fail.
2684 * If there are no such elements, look for a requiredRuntime element.
2686 if (app_config->supported_runtimes != NULL) {
2688 GSList *list = app_config->supported_runtimes;
2689 while (list != NULL) {
2690 version = (char*) list->data;
2691 runtime = get_runtime_by_version (version);
2692 if (runtime != NULL)
2693 runtimes [n++] = runtime;
2694 list = g_slist_next (list);
2696 runtimes [n] = NULL;
2697 app_config_free (app_config);
2701 /* Check the requiredRuntime element. This is for 1.0 apps only. */
2702 if (app_config->required_runtime != NULL) {
2703 runtimes [0] = get_runtime_by_version (app_config->required_runtime);
2704 runtimes [1] = NULL;
2705 app_config_free (app_config);
2708 app_config_free (app_config);
2711 /* Look for a runtime with the exact version */
2712 image = mono_assembly_open_from_bundle (exe_file, NULL, FALSE);
2715 image = mono_image_open (exe_file, NULL);
2717 if (image == NULL) {
2718 /* The image is wrong or the file was not found. In this case return
2719 * a default runtime and leave to the initialization method the work of
2720 * reporting the error.
2722 runtimes [0] = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
2723 runtimes [1] = NULL;
2729 runtimes [0] = get_runtime_by_version (image->version);
2730 runtimes [1] = NULL;
2735 * mono_get_runtime_info:
2737 * Returns: the version of the current runtime instance.
2739 const MonoRuntimeInfo*
2740 mono_get_runtime_info (void)
2742 return current_runtime;
2746 mono_debugger_check_runtime_version (const char *filename)
2748 const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
2749 const MonoRuntimeInfo *rinfo;
2752 get_runtimes_from_exe (filename, &image, runtimes);
2753 rinfo = runtimes [0];
2756 return g_strdup_printf ("Cannot get runtime version from assembly `%s'", filename);
2758 if (rinfo != current_runtime)
2759 return g_strdup_printf ("The Mono Debugger is currently using the `%s' runtime, but "
2760 "the assembly `%s' requires version `%s'", current_runtime->runtime_version,
2761 filename, rinfo->runtime_version);
2767 * mono_framework_version:
2769 * Return the major version of the framework curently executing.
2772 mono_framework_version (void)
2774 return current_runtime->framework_version [0] - '0';
2778 mono_enable_debug_domain_unload (gboolean enable)
2780 debug_domain_unload = enable;
2783 MonoAotCacheConfig *
2784 mono_get_aot_cache_config (void)
2786 return &aot_cache_config;