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;
93 gboolean mono_dont_free_domains;
95 #define mono_appdomains_lock() EnterCriticalSection (&appdomains_mutex)
96 #define mono_appdomains_unlock() LeaveCriticalSection (&appdomains_mutex)
97 static CRITICAL_SECTION appdomains_mutex;
99 static MonoDomain *mono_root_domain = NULL;
101 /* some statistics */
102 static int max_domain_code_size = 0;
103 static int max_domain_code_alloc = 0;
104 static int total_domain_code_alloc = 0;
106 /* AppConfigInfo: Information about runtime versions supported by an
110 GSList *supported_runtimes;
111 char *required_runtime;
112 int configuration_count;
116 static const MonoRuntimeInfo *current_runtime = NULL;
118 static MonoJitInfoFindInAot jit_info_find_in_aot_func = NULL;
120 /* This is the list of runtime versions supported by this JIT.
122 static const MonoRuntimeInfo supported_runtimes[] = {
123 {"v2.0.50215","2.0", { {2,0,0,0}, { 8,0,0,0}, {3,5,0,0}, {3,0,0,0} } },
124 {"v2.0.50727","2.0", { {2,0,0,0}, { 8,0,0,0}, {3,5,0,0}, {3,0,0,0} } },
125 {"v4.0.30319","4.5", { {4,0,0,0}, {10,0,0,0}, {4,0,0,0}, {4,0,0,0} } },
126 {"v4.0.30128","4.0", { {4,0,0,0}, {10,0,0,0}, {4,0,0,0}, {4,0,0,0} } },
127 {"v4.0.20506","4.0", { {4,0,0,0}, {10,0,0,0}, {4,0,0,0}, {4,0,0,0} } },
128 {"mobile", "2.1", { {2,0,5,0}, {10,0,0,0}, {2,0,5,0}, {2,0,5,0} } },
129 {"moonlight", "2.1", { {2,0,5,0}, { 9,0,0,0}, {3,5,0,0}, {3,0,0,0} } },
133 /* The stable runtime version */
134 #define DEFAULT_RUNTIME_VERSION "v2.0.50727"
136 /* Callbacks installed by the JIT */
137 static MonoCreateDomainFunc create_domain_hook;
138 static MonoFreeDomainFunc free_domain_hook;
140 /* This is intentionally not in the header file, so people don't misuse it. */
141 extern void _mono_debug_init_corlib (MonoDomain *domain);
144 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes);
146 static const MonoRuntimeInfo*
147 get_runtime_by_version (const char *version);
150 mono_domain_get_tls_key (void)
152 return appdomain_thread_id;
156 mono_domain_get_tls_offset (void)
159 MONO_THREAD_VAR_OFFSET (tls_appdomain, offset);
160 /* __asm ("jmp 1f; .section writetext, \"awx\"; 1: movl $tls_appdomain@ntpoff, %0; jmp 2f; .previous; 2:"
165 #define JIT_INFO_TABLE_FILL_RATIO_NOM 3
166 #define JIT_INFO_TABLE_FILL_RATIO_DENOM 4
167 #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)
169 #define JIT_INFO_TABLE_LOW_WATERMARK(n) ((n) / 2)
170 #define JIT_INFO_TABLE_HIGH_WATERMARK(n) ((n) * 5 / 6)
172 #define JIT_INFO_TOMBSTONE_MARKER ((MonoMethod*)NULL)
173 #define IS_JIT_INFO_TOMBSTONE(ji) ((ji)->d.method == JIT_INFO_TOMBSTONE_MARKER)
175 #define JIT_INFO_TABLE_HAZARD_INDEX 0
176 #define JIT_INFO_HAZARD_INDEX 1
179 jit_info_table_num_elements (MonoJitInfoTable *table)
182 int num_elements = 0;
184 for (i = 0; i < table->num_chunks; ++i) {
185 MonoJitInfoTableChunk *chunk = table->chunks [i];
186 int chunk_num_elements = chunk->num_elements;
189 for (j = 0; j < chunk_num_elements; ++j) {
190 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j]))
198 static MonoJitInfoTableChunk*
199 jit_info_table_new_chunk (void)
201 MonoJitInfoTableChunk *chunk = g_new0 (MonoJitInfoTableChunk, 1);
207 static MonoJitInfoTable *
208 jit_info_table_new (MonoDomain *domain)
210 MonoJitInfoTable *table = g_malloc0 (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*));
212 table->domain = domain;
213 table->num_chunks = 1;
214 table->chunks [0] = jit_info_table_new_chunk ();
220 jit_info_table_free (MonoJitInfoTable *table)
223 int num_chunks = table->num_chunks;
224 MonoDomain *domain = table->domain;
226 mono_domain_lock (domain);
228 table->domain->num_jit_info_tables--;
229 if (table->domain->num_jit_info_tables <= 1) {
232 for (list = table->domain->jit_info_free_queue; list; list = list->next)
235 g_slist_free (table->domain->jit_info_free_queue);
236 table->domain->jit_info_free_queue = NULL;
239 /* At this point we assume that there are no other threads
240 still accessing the table, so we don't have to worry about
241 hazardous pointers. */
243 for (i = 0; i < num_chunks; ++i) {
244 MonoJitInfoTableChunk *chunk = table->chunks [i];
248 if (--chunk->refcount > 0)
251 num_elements = chunk->num_elements;
252 for (j = 0; j < num_elements; ++j) {
253 MonoJitInfo *ji = chunk->data [j];
255 if (IS_JIT_INFO_TOMBSTONE (ji))
262 mono_domain_unlock (domain);
267 /* The jit_info_table is sorted in ascending order by the end
268 * addresses of the compiled methods. The reason why we have to do
269 * this is that once we introduce tombstones, it becomes possible for
270 * code ranges to overlap, and if we sort by code start and insert at
271 * the back of the table, we cannot guarantee that we won't overlook
274 * There are actually two possible ways to do the sorting and
275 * inserting which work with our lock-free mechanism:
277 * 1. Sort by start address and insert at the front. When looking for
278 * an entry, find the last one with a start address lower than the one
279 * you're looking for, then work your way to the front of the table.
281 * 2. Sort by end address and insert at the back. When looking for an
282 * entry, find the first one with an end address higher than the one
283 * you're looking for, then work your way to the end of the table.
285 * We chose the latter out of convenience.
288 jit_info_table_index (MonoJitInfoTable *table, gint8 *addr)
290 int left = 0, right = table->num_chunks;
292 g_assert (left < right);
295 int pos = (left + right) / 2;
296 MonoJitInfoTableChunk *chunk = table->chunks [pos];
298 if (addr < chunk->last_code_end)
302 } while (left < right);
303 g_assert (left == right);
305 if (left >= table->num_chunks)
306 return table->num_chunks - 1;
311 jit_info_table_chunk_index (MonoJitInfoTableChunk *chunk, MonoThreadHazardPointers *hp, gint8 *addr)
313 int left = 0, right = chunk->num_elements;
315 while (left < right) {
316 int pos = (left + right) / 2;
317 MonoJitInfo *ji = get_hazardous_pointer((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
318 gint8 *code_end = (gint8*)ji->code_start + ji->code_size;
325 g_assert (left == right);
331 jit_info_table_find (MonoJitInfoTable *table, MonoThreadHazardPointers *hp, gint8 *addr)
336 chunk_pos = jit_info_table_index (table, (gint8*)addr);
337 g_assert (chunk_pos < table->num_chunks);
339 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], hp, (gint8*)addr);
341 /* We now have a position that's very close to that of the
342 first element whose end address is higher than the one
343 we're looking for. If we don't have the exact position,
344 then we have a position below that one, so we'll just
345 search upward until we find our element. */
347 MonoJitInfoTableChunk *chunk = table->chunks [chunk_pos];
349 while (pos < chunk->num_elements) {
350 ji = get_hazardous_pointer ((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
354 if (IS_JIT_INFO_TOMBSTONE (ji)) {
355 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
358 if ((gint8*)addr >= (gint8*)ji->code_start
359 && (gint8*)addr < (gint8*)ji->code_start + ji->code_size) {
360 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
364 /* If we find a non-tombstone element which is already
365 beyond what we're looking for, we have to end the
367 if ((gint8*)addr < (gint8*)ji->code_start)
373 } while (chunk_pos < table->num_chunks);
377 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
382 * mono_jit_info_table_find_internal:
384 * If TRY_AOT is FALSE, avoid loading information for missing methods from AOT images, which is currently not async safe.
385 * In this case, only those AOT methods will be found whose jit info is already loaded.
386 * ASYNC SAFETY: When called in an async context (mono_thread_info_is_async_context ()), this is async safe.
387 * In this case, the returned MonoJitInfo might not have metadata information, in particular,
388 * mono_jit_info_get_method () could fail.
391 mono_jit_info_table_find_internal (MonoDomain *domain, char *addr, gboolean try_aot)
393 MonoJitInfoTable *table;
394 MonoJitInfo *ji, *module_ji;
395 MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
397 ++mono_stats.jit_info_table_lookup_count;
399 /* First we have to get the domain's jit_info_table. This is
400 complicated by the fact that a writer might substitute a
401 new table and free the old one. What the writer guarantees
402 us is that it looks at the hazard pointers after it has
403 changed the jit_info_table pointer. So, if we guard the
404 table by a hazard pointer and make sure that the pointer is
405 still there after we've made it hazardous, we don't have to
406 worry about the writer freeing the table. */
407 table = get_hazardous_pointer ((gpointer volatile*)&domain->jit_info_table, hp, JIT_INFO_TABLE_HAZARD_INDEX);
409 ji = jit_info_table_find (table, hp, (gint8*)addr);
411 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
415 /* Maybe its an AOT module */
416 if (try_aot && mono_root_domain && mono_root_domain->aot_modules) {
417 table = get_hazardous_pointer ((gpointer volatile*)&mono_root_domain->aot_modules, hp, JIT_INFO_TABLE_HAZARD_INDEX);
418 module_ji = jit_info_table_find (table, hp, (gint8*)addr);
420 ji = jit_info_find_in_aot_func (domain, module_ji->d.image, addr);
422 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
429 mono_jit_info_table_find (MonoDomain *domain, char *addr)
431 return mono_jit_info_table_find_internal (domain, addr, TRUE);
434 static G_GNUC_UNUSED void
435 jit_info_table_check (MonoJitInfoTable *table)
439 for (i = 0; i < table->num_chunks; ++i) {
440 MonoJitInfoTableChunk *chunk = table->chunks [i];
443 g_assert (chunk->refcount > 0 /* && chunk->refcount <= 8 */);
444 if (chunk->refcount > 10)
445 printf("warning: chunk refcount is %d\n", chunk->refcount);
446 g_assert (chunk->num_elements <= MONO_JIT_INFO_TABLE_CHUNK_SIZE);
448 for (j = 0; j < chunk->num_elements; ++j) {
449 MonoJitInfo *this = chunk->data [j];
452 g_assert ((gint8*)this->code_start + this->code_size <= chunk->last_code_end);
454 if (j < chunk->num_elements - 1)
455 next = chunk->data [j + 1];
456 else if (i < table->num_chunks - 1) {
459 for (k = i + 1; k < table->num_chunks; ++k)
460 if (table->chunks [k]->num_elements > 0)
463 if (k >= table->num_chunks)
466 g_assert (table->chunks [k]->num_elements > 0);
467 next = table->chunks [k]->data [0];
471 g_assert ((gint8*)this->code_start + this->code_size <= (gint8*)next->code_start + next->code_size);
476 static MonoJitInfoTable*
477 jit_info_table_realloc (MonoJitInfoTable *old)
480 int num_elements = jit_info_table_num_elements (old);
483 int new_chunk, new_element;
484 MonoJitInfoTable *new;
486 /* number of needed places for elements needed */
487 required_size = (int)((long)num_elements * JIT_INFO_TABLE_FILL_RATIO_DENOM / JIT_INFO_TABLE_FILL_RATIO_NOM);
488 num_chunks = (required_size + MONO_JIT_INFO_TABLE_CHUNK_SIZE - 1) / MONO_JIT_INFO_TABLE_CHUNK_SIZE;
489 if (num_chunks == 0) {
490 g_assert (num_elements == 0);
491 return jit_info_table_new (old->domain);
493 g_assert (num_chunks > 0);
495 new = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*) * num_chunks);
496 new->domain = old->domain;
497 new->num_chunks = num_chunks;
499 for (i = 0; i < num_chunks; ++i)
500 new->chunks [i] = jit_info_table_new_chunk ();
504 for (i = 0; i < old->num_chunks; ++i) {
505 MonoJitInfoTableChunk *chunk = old->chunks [i];
506 int chunk_num_elements = chunk->num_elements;
509 for (j = 0; j < chunk_num_elements; ++j) {
510 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j])) {
511 g_assert (new_chunk < num_chunks);
512 new->chunks [new_chunk]->data [new_element] = chunk->data [j];
513 if (++new_element >= JIT_INFO_TABLE_FILLED_NUM_ELEMENTS) {
514 new->chunks [new_chunk]->num_elements = new_element;
522 if (new_chunk < num_chunks) {
523 g_assert (new_chunk == num_chunks - 1);
524 new->chunks [new_chunk]->num_elements = new_element;
525 g_assert (new->chunks [new_chunk]->num_elements > 0);
528 for (i = 0; i < num_chunks; ++i) {
529 MonoJitInfoTableChunk *chunk = new->chunks [i];
530 MonoJitInfo *ji = chunk->data [chunk->num_elements - 1];
532 new->chunks [i]->last_code_end = (gint8*)ji->code_start + ji->code_size;
539 jit_info_table_split_chunk (MonoJitInfoTableChunk *chunk, MonoJitInfoTableChunk **new1p, MonoJitInfoTableChunk **new2p)
541 MonoJitInfoTableChunk *new1 = jit_info_table_new_chunk ();
542 MonoJitInfoTableChunk *new2 = jit_info_table_new_chunk ();
544 g_assert (chunk->num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE);
546 new1->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE / 2;
547 new2->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE - new1->num_elements;
549 memcpy ((void*)new1->data, (void*)chunk->data, sizeof (MonoJitInfo*) * new1->num_elements);
550 memcpy ((void*)new2->data, (void*)(chunk->data + new1->num_elements), sizeof (MonoJitInfo*) * new2->num_elements);
552 new1->last_code_end = (gint8*)new1->data [new1->num_elements - 1]->code_start
553 + new1->data [new1->num_elements - 1]->code_size;
554 new2->last_code_end = (gint8*)new2->data [new2->num_elements - 1]->code_start
555 + new2->data [new2->num_elements - 1]->code_size;
561 static MonoJitInfoTable*
562 jit_info_table_copy_and_split_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
564 MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
565 + sizeof (MonoJitInfoTableChunk*) * (table->num_chunks + 1));
568 new_table->domain = table->domain;
569 new_table->num_chunks = table->num_chunks + 1;
572 for (i = 0; i < table->num_chunks; ++i) {
573 if (table->chunks [i] == chunk) {
574 jit_info_table_split_chunk (chunk, &new_table->chunks [j], &new_table->chunks [j + 1]);
577 new_table->chunks [j] = table->chunks [i];
578 ++new_table->chunks [j]->refcount;
583 g_assert (j == new_table->num_chunks);
588 static MonoJitInfoTableChunk*
589 jit_info_table_purify_chunk (MonoJitInfoTableChunk *old)
591 MonoJitInfoTableChunk *new = jit_info_table_new_chunk ();
595 for (i = 0; i < old->num_elements; ++i) {
596 if (!IS_JIT_INFO_TOMBSTONE (old->data [i]))
597 new->data [j++] = old->data [i];
600 new->num_elements = j;
601 if (new->num_elements > 0)
602 new->last_code_end = (gint8*)new->data [j - 1]->code_start + new->data [j - 1]->code_size;
604 new->last_code_end = old->last_code_end;
609 static MonoJitInfoTable*
610 jit_info_table_copy_and_purify_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
612 MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
613 + sizeof (MonoJitInfoTableChunk*) * table->num_chunks);
616 new_table->domain = table->domain;
617 new_table->num_chunks = table->num_chunks;
620 for (i = 0; i < table->num_chunks; ++i) {
621 if (table->chunks [i] == chunk)
622 new_table->chunks [j++] = jit_info_table_purify_chunk (table->chunks [i]);
624 new_table->chunks [j] = table->chunks [i];
625 ++new_table->chunks [j]->refcount;
630 g_assert (j == new_table->num_chunks);
635 /* As we add an element to the table the case can arise that the chunk
636 * to which we need to add is already full. In that case we have to
637 * allocate a new table and do something about that chunk. We have
638 * several strategies:
640 * If the number of elements in the table is below the low watermark
641 * or above the high watermark, we reallocate the whole table.
642 * Otherwise we only concern ourselves with the overflowing chunk:
644 * If there are no tombstones in the chunk then we split the chunk in
645 * two, each half full.
647 * If the chunk does contain tombstones, we just make a new copy of
648 * the chunk without the tombstones, which will have room for at least
649 * the one element we have to add.
651 static MonoJitInfoTable*
652 jit_info_table_chunk_overflow (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
654 int num_elements = jit_info_table_num_elements (table);
657 if (num_elements < JIT_INFO_TABLE_LOW_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)
658 || num_elements > JIT_INFO_TABLE_HIGH_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)) {
659 //printf ("reallocing table\n");
660 return jit_info_table_realloc (table);
663 /* count the number of non-tombstone elements in the chunk */
665 for (i = 0; i < chunk->num_elements; ++i) {
666 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [i]))
670 if (num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
671 //printf ("splitting chunk\n");
672 return jit_info_table_copy_and_split_chunk (table, chunk);
675 //printf ("purifying chunk\n");
676 return jit_info_table_copy_and_purify_chunk (table, chunk);
679 /* We add elements to the table by first making space for them by
680 * shifting the elements at the back to the right, one at a time.
681 * This results in duplicate entries during the process, but during
682 * all the time the table is in a sorted state. Also, when an element
683 * is replaced by another one, the element that replaces it has an end
684 * address that is equal to or lower than that of the replaced
685 * element. That property is necessary to guarantee that when
686 * searching for an element we end up at a position not higher than
687 * the one we're looking for (i.e. we either find the element directly
688 * or we end up to the left of it).
691 jit_info_table_add (MonoDomain *domain, MonoJitInfoTable *volatile *table_ptr, MonoJitInfo *ji)
693 MonoJitInfoTable *table;
694 MonoJitInfoTableChunk *chunk;
702 chunk_pos = jit_info_table_index (table, (gint8*)ji->code_start + ji->code_size);
703 g_assert (chunk_pos < table->num_chunks);
704 chunk = table->chunks [chunk_pos];
706 if (chunk->num_elements >= MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
707 MonoJitInfoTable *new_table = jit_info_table_chunk_overflow (table, chunk);
709 /* Debugging code, should be removed. */
710 //jit_info_table_check (new_table);
712 *table_ptr = new_table;
713 mono_memory_barrier ();
714 domain->num_jit_info_tables++;
715 mono_thread_hazardous_free_or_queue (table, (MonoHazardousFreeFunc)jit_info_table_free, TRUE, FALSE);
721 /* Debugging code, should be removed. */
722 //jit_info_table_check (table);
724 num_elements = chunk->num_elements;
726 pos = jit_info_table_chunk_index (chunk, NULL, (gint8*)ji->code_start + ji->code_size);
728 /* First we need to size up the chunk by one, by copying the
729 last item, or inserting the first one, if the table is
731 if (num_elements > 0)
732 chunk->data [num_elements] = chunk->data [num_elements - 1];
734 chunk->data [0] = ji;
735 mono_memory_write_barrier ();
736 chunk->num_elements = ++num_elements;
738 /* Shift the elements up one by one. */
739 for (i = num_elements - 2; i >= pos; --i) {
740 mono_memory_write_barrier ();
741 chunk->data [i + 1] = chunk->data [i];
744 /* Now we have room and can insert the new item. */
745 mono_memory_write_barrier ();
746 chunk->data [pos] = ji;
748 /* Set the high code end address chunk entry. */
749 chunk->last_code_end = (gint8*)chunk->data [chunk->num_elements - 1]->code_start
750 + chunk->data [chunk->num_elements - 1]->code_size;
752 /* Debugging code, should be removed. */
753 //jit_info_table_check (table);
757 mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
759 g_assert (ji->d.method != NULL);
761 mono_domain_lock (domain);
763 ++mono_stats.jit_info_table_insert_count;
765 jit_info_table_add (domain, &domain->jit_info_table, ji);
767 mono_domain_unlock (domain);
771 mono_jit_info_make_tombstone (MonoJitInfo *ji)
773 MonoJitInfo *tombstone = g_new0 (MonoJitInfo, 1);
775 tombstone->code_start = ji->code_start;
776 tombstone->code_size = ji->code_size;
777 tombstone->d.method = JIT_INFO_TOMBSTONE_MARKER;
783 * LOCKING: domain lock
786 mono_jit_info_free_or_queue (MonoDomain *domain, MonoJitInfo *ji)
788 if (domain->num_jit_info_tables <= 1) {
789 /* Can it actually happen that we only have one table
790 but ji is still hazardous? */
791 mono_thread_hazardous_free_or_queue (ji, g_free, TRUE, FALSE);
793 domain->jit_info_free_queue = g_slist_prepend (domain->jit_info_free_queue, ji);
798 jit_info_table_remove (MonoJitInfoTable *table, MonoJitInfo *ji)
800 MonoJitInfoTableChunk *chunk;
801 gpointer start = ji->code_start;
804 chunk_pos = jit_info_table_index (table, start);
805 g_assert (chunk_pos < table->num_chunks);
807 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], NULL, start);
810 chunk = table->chunks [chunk_pos];
812 while (pos < chunk->num_elements) {
813 if (chunk->data [pos] == ji)
816 g_assert (IS_JIT_INFO_TOMBSTONE (chunk->data [pos]));
817 g_assert ((guint8*)chunk->data [pos]->code_start + chunk->data [pos]->code_size
818 <= (guint8*)ji->code_start + ji->code_size);
825 } while (chunk_pos < table->num_chunks);
828 g_assert (chunk->data [pos] == ji);
830 chunk->data [pos] = mono_jit_info_make_tombstone (ji);
832 /* Debugging code, should be removed. */
833 //jit_info_table_check (table);
837 mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
839 MonoJitInfoTable *table;
841 mono_domain_lock (domain);
842 table = domain->jit_info_table;
844 ++mono_stats.jit_info_table_remove_count;
846 jit_info_table_remove (table, ji);
848 mono_jit_info_free_or_queue (domain, ji);
850 mono_domain_unlock (domain);
854 mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
858 mono_appdomains_lock ();
861 * We reuse MonoJitInfoTable to store AOT module info,
862 * this gives us async-safe lookup.
864 g_assert (mono_root_domain);
865 if (!mono_root_domain->aot_modules) {
866 mono_root_domain->num_jit_info_tables ++;
867 mono_root_domain->aot_modules = jit_info_table_new (mono_root_domain);
870 ji = g_new0 (MonoJitInfo, 1);
872 ji->code_start = start;
873 ji->code_size = (guint8*)end - (guint8*)start;
874 jit_info_table_add (mono_root_domain, &mono_root_domain->aot_modules, ji);
876 mono_appdomains_unlock ();
880 mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func)
882 jit_info_find_in_aot_func = func;
886 mono_jit_info_get_code_start (MonoJitInfo* ji)
888 return ji->code_start;
892 mono_jit_info_get_code_size (MonoJitInfo* ji)
894 return ji->code_size;
898 mono_jit_info_get_method (MonoJitInfo* ji)
900 g_assert (!ji->async);
905 jit_info_key_extract (gpointer value)
907 MonoJitInfo *info = (MonoJitInfo*)value;
909 return info->d.method;
913 jit_info_next_value (gpointer value)
915 MonoJitInfo *info = (MonoJitInfo*)value;
917 return (gpointer*)&info->next_jit_code_hash;
921 mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
923 mono_internal_hash_table_init (jit_code_hash,
924 mono_aligned_addr_hash,
925 jit_info_key_extract,
926 jit_info_next_value);
930 mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
932 if (ji->has_generic_jit_info)
933 return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
939 * mono_jit_info_get_generic_sharing_context:
942 * Returns the jit info's generic sharing context, or NULL if it
945 MonoGenericSharingContext*
946 mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
948 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
951 return gi->generic_sharing_context;
957 * mono_jit_info_set_generic_sharing_context:
959 * @gsctx: a generic sharing context
961 * Sets the jit info's generic sharing context. The jit info must
962 * have memory allocated for the context.
965 mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
967 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
971 gi->generic_sharing_context = gsctx;
974 MonoTryBlockHoleTableJitInfo*
975 mono_jit_info_get_try_block_hole_table_info (MonoJitInfo *ji)
977 if (ji->has_try_block_holes) {
978 char *ptr = (char*)&ji->clauses [ji->num_clauses];
979 if (ji->has_generic_jit_info)
980 ptr += sizeof (MonoGenericJitInfo);
981 return (MonoTryBlockHoleTableJitInfo*)ptr;
988 mono_jit_info_get_arch_eh_info (MonoJitInfo *ji)
990 if (ji->has_arch_eh_info) {
991 char *ptr = (char*)&ji->clauses [ji->num_clauses];
992 if (ji->has_generic_jit_info)
993 ptr += sizeof (MonoGenericJitInfo);
994 if (ji->has_try_block_holes)
995 ptr += sizeof (MonoTryBlockHoleTableJitInfo);
996 return (MonoArchEHJitInfo*)ptr;
1003 mono_jit_info_get_cas_info (MonoJitInfo *ji)
1005 if (ji->has_cas_info) {
1006 char *ptr = (char*)&ji->clauses [ji->num_clauses];
1007 if (ji->has_generic_jit_info)
1008 ptr += sizeof (MonoGenericJitInfo);
1009 if (ji->has_try_block_holes)
1010 ptr += sizeof (MonoTryBlockHoleTableJitInfo);
1011 if (ji->has_arch_eh_info)
1012 ptr += sizeof (MonoArchEHJitInfo);
1013 return (MonoMethodCasInfo*)ptr;
1019 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
1020 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
1022 static LockFreeMempool*
1023 lock_free_mempool_new (void)
1025 return g_new0 (LockFreeMempool, 1);
1029 lock_free_mempool_free (LockFreeMempool *mp)
1031 LockFreeMempoolChunk *chunk, *next;
1036 mono_vfree (chunk, mono_pagesize ());
1043 * This is async safe
1045 static LockFreeMempoolChunk*
1046 lock_free_mempool_chunk_new (LockFreeMempool *mp, int len)
1048 LockFreeMempoolChunk *chunk, *prev;
1051 size = mono_pagesize ();
1052 while (size - sizeof (LockFreeMempoolChunk) < len)
1053 size += mono_pagesize ();
1054 chunk = mono_valloc (0, size, MONO_MMAP_READ|MONO_MMAP_WRITE);
1056 chunk->mem = ALIGN_PTR_TO ((char*)chunk + sizeof (LockFreeMempoolChunk), 16);
1057 chunk->size = ((char*)chunk + size) - (char*)chunk->mem;
1060 /* Add to list of chunks lock-free */
1063 if (InterlockedCompareExchangePointer ((volatile gpointer*)&mp->chunks, chunk, prev) == prev)
1072 * This is async safe
1075 lock_free_mempool_alloc0 (LockFreeMempool *mp, guint size)
1077 LockFreeMempoolChunk *chunk;
1081 // FIXME: Free the allocator
1083 size = ALIGN_TO (size, 8);
1084 chunk = mp->current;
1086 chunk = lock_free_mempool_chunk_new (mp, size);
1087 mono_memory_barrier ();
1089 mp->current = chunk;
1092 /* The code below is lock-free, 'chunk' is shared state */
1093 oldpos = InterlockedExchangeAdd (&chunk->pos, size);
1094 if (oldpos + size > chunk->size) {
1095 chunk = lock_free_mempool_chunk_new (mp, size);
1096 g_assert (chunk->pos + size <= chunk->size);
1099 mono_memory_barrier ();
1100 mp->current = chunk;
1102 res = (char*)chunk->mem + oldpos;
1109 mono_install_create_domain_hook (MonoCreateDomainFunc func)
1111 create_domain_hook = func;
1115 mono_install_free_domain_hook (MonoFreeDomainFunc func)
1117 free_domain_hook = func;
1121 * mono_string_equal:
1122 * @s1: First string to compare
1123 * @s2: Second string to compare
1125 * Returns FALSE if the strings differ.
1128 mono_string_equal (MonoString *s1, MonoString *s2)
1130 int l1 = mono_string_length (s1);
1131 int l2 = mono_string_length (s2);
1138 return memcmp (mono_string_chars (s1), mono_string_chars (s2), l1 * 2) == 0;
1143 * @s: the string to hash
1145 * Returns the hash for the string.
1148 mono_string_hash (MonoString *s)
1150 const guint16 *p = mono_string_chars (s);
1151 int i, len = mono_string_length (s);
1154 for (i = 0; i < len; i++) {
1155 h = (h << 5) - h + *p;
1163 mono_ptrarray_equal (gpointer *s1, gpointer *s2)
1165 int len = GPOINTER_TO_INT (s1 [0]);
1166 if (len != GPOINTER_TO_INT (s2 [0]))
1169 return memcmp (s1 + 1, s2 + 1, len * sizeof(gpointer)) == 0;
1173 mono_ptrarray_hash (gpointer *s)
1176 int len = GPOINTER_TO_INT (s [0]);
1179 for (i = 1; i < len; i++)
1180 hash += GPOINTER_TO_UINT (s [i]);
1186 * Allocate an id for domain and set domain->domain_id.
1187 * LOCKING: must be called while holding appdomains_mutex.
1188 * We try to assign low numbers to the domain, so it can be used
1189 * as an index in data tables to lookup domain-specific info
1190 * with minimal memory overhead. We also try not to reuse the
1191 * same id too quickly (to help debugging).
1194 domain_id_alloc (MonoDomain *domain)
1197 if (!appdomains_list) {
1198 appdomain_list_size = 2;
1199 appdomains_list = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1201 for (i = appdomain_next; i < appdomain_list_size; ++i) {
1202 if (!appdomains_list [i]) {
1208 for (i = 0; i < appdomain_next; ++i) {
1209 if (!appdomains_list [i]) {
1216 MonoDomain **new_list;
1217 int new_size = appdomain_list_size * 2;
1218 if (new_size >= (1 << 16))
1219 g_assert_not_reached ();
1220 id = appdomain_list_size;
1221 new_list = mono_gc_alloc_fixed (new_size * sizeof (void*), NULL);
1222 memcpy (new_list, appdomains_list, appdomain_list_size * sizeof (void*));
1223 mono_gc_free_fixed (appdomains_list);
1224 appdomains_list = new_list;
1225 appdomain_list_size = new_size;
1227 domain->domain_id = id;
1228 appdomains_list [id] = domain;
1230 if (appdomain_next > appdomain_list_size)
1235 static gsize domain_gc_bitmap [sizeof(MonoDomain)/4/32 + 1];
1236 static gpointer domain_gc_desc = NULL;
1237 static guint32 domain_shadow_serial = 0L;
1240 mono_domain_create (void)
1243 guint32 shadow_serial;
1245 mono_appdomains_lock ();
1246 shadow_serial = domain_shadow_serial++;
1248 if (!domain_gc_desc) {
1249 unsigned int i, bit = 0;
1250 for (i = G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_OBJECT); i < G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_GC_TRACKED); i += sizeof (gpointer)) {
1251 bit = i / sizeof (gpointer);
1252 domain_gc_bitmap [bit / 32] |= (gsize) 1 << (bit % 32);
1254 domain_gc_desc = mono_gc_make_descr_from_bitmap ((gsize*)domain_gc_bitmap, bit + 1);
1256 mono_appdomains_unlock ();
1258 #ifdef HAVE_BOEHM_GC
1260 * Boehm doesn't like roots inside GC allocated objects, and alloc_fixed returns
1261 * a GC_MALLOC-ed object, contrary to the api docs. This causes random crashes when
1262 * running the corlib test suite.
1263 * To solve this, we pass a NULL descriptor, and don't register roots.
1265 domain = mono_gc_alloc_fixed (sizeof (MonoDomain), NULL);
1267 domain = mono_gc_alloc_fixed (sizeof (MonoDomain), domain_gc_desc);
1268 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);
1270 domain->shadow_serial = shadow_serial;
1271 domain->domain = NULL;
1272 domain->setup = NULL;
1273 domain->friendly_name = NULL;
1274 domain->search_path = NULL;
1276 mono_profiler_appdomain_event (domain, MONO_PROFILE_START_LOAD);
1278 domain->mp = mono_mempool_new ();
1279 domain->code_mp = mono_code_manager_new ();
1280 domain->lock_free_mp = lock_free_mempool_new ();
1281 domain->env = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1282 domain->domain_assemblies = NULL;
1283 domain->assembly_bindings = NULL;
1284 domain->assembly_bindings_parsed = FALSE;
1285 domain->class_vtable_array = g_ptr_array_new ();
1286 domain->proxy_vtable_hash = g_hash_table_new ((GHashFunc)mono_ptrarray_hash, (GCompareFunc)mono_ptrarray_equal);
1287 domain->static_data_array = NULL;
1288 mono_jit_code_hash_init (&domain->jit_code_hash);
1289 domain->ldstr_table = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1290 domain->num_jit_info_tables = 1;
1291 domain->jit_info_table = jit_info_table_new (domain);
1292 domain->jit_info_free_queue = NULL;
1293 domain->finalizable_objects_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1294 domain->ftnptrs_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1296 InitializeCriticalSection (&domain->lock);
1297 InitializeCriticalSection (&domain->assemblies_lock);
1298 InitializeCriticalSection (&domain->jit_code_hash_lock);
1299 InitializeCriticalSection (&domain->finalizable_objects_hash_lock);
1301 domain->method_rgctx_hash = NULL;
1303 mono_appdomains_lock ();
1304 domain_id_alloc (domain);
1305 mono_appdomains_unlock ();
1307 #ifndef DISABLE_PERFCOUNTERS
1308 mono_perfcounters->loader_appdomains++;
1309 mono_perfcounters->loader_total_appdomains++;
1312 mono_debug_domain_create (domain);
1314 if (create_domain_hook)
1315 create_domain_hook (domain);
1317 mono_profiler_appdomain_loaded (domain, MONO_PROFILE_OK);
1323 * mono_init_internal:
1325 * Creates the initial application domain and initializes the mono_defaults
1327 * This function is guaranteed to not run any IL code.
1328 * If exe_filename is not NULL, the method will determine the required runtime
1329 * from the exe configuration file or the version PE field.
1330 * If runtime_version is not NULL, that runtime version will be used.
1331 * Either exe_filename or runtime_version must be provided.
1333 * Returns: the initial domain.
1336 mono_init_internal (const char *filename, const char *exe_filename, const char *runtime_version)
1338 static MonoDomain *domain = NULL;
1339 MonoAssembly *ass = NULL;
1340 MonoImageOpenStatus status = MONO_IMAGE_OK;
1341 const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
1345 g_assert_not_reached ();
1348 /* Avoid system error message boxes. */
1349 SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1356 #ifndef DISABLE_PERFCOUNTERS
1357 mono_perfcounters_init ();
1360 mono_counters_register ("Max native code in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_size);
1361 mono_counters_register ("Max code space allocated in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_alloc);
1362 mono_counters_register ("Total code space allocated", MONO_COUNTER_INT|MONO_COUNTER_JIT, &total_domain_code_alloc);
1364 mono_gc_base_init ();
1366 MONO_FAST_TLS_INIT (tls_appdomain);
1367 mono_native_tls_alloc (&appdomain_thread_id, NULL);
1369 InitializeCriticalSection (&appdomains_mutex);
1371 mono_metadata_init ();
1372 mono_images_init ();
1373 mono_assemblies_init ();
1374 mono_classes_init ();
1375 mono_loader_init ();
1376 mono_reflection_init ();
1377 mono_runtime_init_tls ();
1379 /* FIXME: When should we release this memory? */
1380 MONO_GC_REGISTER_ROOT_FIXED (appdomains_list);
1382 domain = mono_domain_create ();
1383 mono_root_domain = domain;
1385 SET_APPDOMAIN (domain);
1387 /* Get a list of runtimes supported by the exe */
1388 if (exe_filename != NULL) {
1390 * This function will load the exe file as a MonoImage. We need to close it, but
1391 * that would mean it would be reloaded later. So instead, we save it to
1392 * exe_image, and close it during shutdown.
1394 get_runtimes_from_exe (exe_filename, &exe_image, runtimes);
1397 exe_image = mono_assembly_open_from_bundle (exe_filename, NULL, FALSE);
1399 exe_image = mono_image_open (exe_filename, NULL);
1401 mono_fixup_exe_image (exe_image);
1403 } else if (runtime_version != NULL) {
1404 runtimes [0] = get_runtime_by_version (runtime_version);
1405 runtimes [1] = NULL;
1408 if (runtimes [0] == NULL) {
1409 const MonoRuntimeInfo *default_runtime = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
1410 runtimes [0] = default_runtime;
1411 runtimes [1] = NULL;
1412 g_print ("WARNING: The runtime version supported by this application is unavailable.\n");
1413 g_print ("Using default runtime: %s\n", default_runtime->runtime_version);
1416 /* The selected runtime will be the first one for which there is a mscrolib.dll */
1417 for (n = 0; runtimes [n] != NULL && ass == NULL; n++) {
1418 current_runtime = runtimes [n];
1419 ass = mono_assembly_load_corlib (current_runtime, &status);
1420 if (status != MONO_IMAGE_OK && status != MONO_IMAGE_ERROR_ERRNO)
1425 if ((status != MONO_IMAGE_OK) || (ass == NULL)) {
1427 case MONO_IMAGE_ERROR_ERRNO: {
1428 char *corlib_file = g_build_filename (mono_assembly_getrootdir (), "mono", current_runtime->framework_version, "mscorlib.dll", NULL);
1429 g_print ("The assembly mscorlib.dll was not found or could not be loaded.\n");
1430 g_print ("It should have been installed in the `%s' directory.\n", corlib_file);
1431 g_free (corlib_file);
1434 case MONO_IMAGE_IMAGE_INVALID:
1435 g_print ("The file %s/mscorlib.dll is an invalid CIL image\n",
1436 mono_assembly_getrootdir ());
1438 case MONO_IMAGE_MISSING_ASSEMBLYREF:
1439 g_print ("Missing assembly reference in %s/mscorlib.dll\n",
1440 mono_assembly_getrootdir ());
1443 /* to suppress compiler warning */
1449 mono_defaults.corlib = mono_assembly_get_image (ass);
1451 mono_defaults.object_class = mono_class_from_name (
1452 mono_defaults.corlib, "System", "Object");
1453 g_assert (mono_defaults.object_class != 0);
1455 mono_defaults.void_class = mono_class_from_name (
1456 mono_defaults.corlib, "System", "Void");
1457 g_assert (mono_defaults.void_class != 0);
1459 mono_defaults.boolean_class = mono_class_from_name (
1460 mono_defaults.corlib, "System", "Boolean");
1461 g_assert (mono_defaults.boolean_class != 0);
1463 mono_defaults.byte_class = mono_class_from_name (
1464 mono_defaults.corlib, "System", "Byte");
1465 g_assert (mono_defaults.byte_class != 0);
1467 mono_defaults.sbyte_class = mono_class_from_name (
1468 mono_defaults.corlib, "System", "SByte");
1469 g_assert (mono_defaults.sbyte_class != 0);
1471 mono_defaults.int16_class = mono_class_from_name (
1472 mono_defaults.corlib, "System", "Int16");
1473 g_assert (mono_defaults.int16_class != 0);
1475 mono_defaults.uint16_class = mono_class_from_name (
1476 mono_defaults.corlib, "System", "UInt16");
1477 g_assert (mono_defaults.uint16_class != 0);
1479 mono_defaults.int32_class = mono_class_from_name (
1480 mono_defaults.corlib, "System", "Int32");
1481 g_assert (mono_defaults.int32_class != 0);
1483 mono_defaults.uint32_class = mono_class_from_name (
1484 mono_defaults.corlib, "System", "UInt32");
1485 g_assert (mono_defaults.uint32_class != 0);
1487 mono_defaults.uint_class = mono_class_from_name (
1488 mono_defaults.corlib, "System", "UIntPtr");
1489 g_assert (mono_defaults.uint_class != 0);
1491 mono_defaults.int_class = mono_class_from_name (
1492 mono_defaults.corlib, "System", "IntPtr");
1493 g_assert (mono_defaults.int_class != 0);
1495 mono_defaults.int64_class = mono_class_from_name (
1496 mono_defaults.corlib, "System", "Int64");
1497 g_assert (mono_defaults.int64_class != 0);
1499 mono_defaults.uint64_class = mono_class_from_name (
1500 mono_defaults.corlib, "System", "UInt64");
1501 g_assert (mono_defaults.uint64_class != 0);
1503 mono_defaults.single_class = mono_class_from_name (
1504 mono_defaults.corlib, "System", "Single");
1505 g_assert (mono_defaults.single_class != 0);
1507 mono_defaults.double_class = mono_class_from_name (
1508 mono_defaults.corlib, "System", "Double");
1509 g_assert (mono_defaults.double_class != 0);
1511 mono_defaults.char_class = mono_class_from_name (
1512 mono_defaults.corlib, "System", "Char");
1513 g_assert (mono_defaults.char_class != 0);
1515 mono_defaults.string_class = mono_class_from_name (
1516 mono_defaults.corlib, "System", "String");
1517 g_assert (mono_defaults.string_class != 0);
1519 mono_defaults.enum_class = mono_class_from_name (
1520 mono_defaults.corlib, "System", "Enum");
1521 g_assert (mono_defaults.enum_class != 0);
1523 mono_defaults.array_class = mono_class_from_name (
1524 mono_defaults.corlib, "System", "Array");
1525 g_assert (mono_defaults.array_class != 0);
1527 mono_defaults.delegate_class = mono_class_from_name (
1528 mono_defaults.corlib, "System", "Delegate");
1529 g_assert (mono_defaults.delegate_class != 0 );
1531 mono_defaults.multicastdelegate_class = mono_class_from_name (
1532 mono_defaults.corlib, "System", "MulticastDelegate");
1533 g_assert (mono_defaults.multicastdelegate_class != 0 );
1535 mono_defaults.asyncresult_class = mono_class_from_name (
1536 mono_defaults.corlib, "System.Runtime.Remoting.Messaging",
1538 g_assert (mono_defaults.asyncresult_class != 0 );
1540 mono_defaults.manualresetevent_class = mono_class_from_name (
1541 mono_defaults.corlib, "System.Threading", "ManualResetEvent");
1542 g_assert (mono_defaults.manualresetevent_class != 0 );
1544 mono_defaults.typehandle_class = mono_class_from_name (
1545 mono_defaults.corlib, "System", "RuntimeTypeHandle");
1546 g_assert (mono_defaults.typehandle_class != 0);
1548 mono_defaults.methodhandle_class = mono_class_from_name (
1549 mono_defaults.corlib, "System", "RuntimeMethodHandle");
1550 g_assert (mono_defaults.methodhandle_class != 0);
1552 mono_defaults.fieldhandle_class = mono_class_from_name (
1553 mono_defaults.corlib, "System", "RuntimeFieldHandle");
1554 g_assert (mono_defaults.fieldhandle_class != 0);
1556 mono_defaults.systemtype_class = mono_class_from_name (
1557 mono_defaults.corlib, "System", "Type");
1558 g_assert (mono_defaults.systemtype_class != 0);
1560 mono_defaults.monotype_class = mono_class_from_name (
1561 mono_defaults.corlib, "System", "MonoType");
1562 g_assert (mono_defaults.monotype_class != 0);
1564 mono_defaults.exception_class = mono_class_from_name (
1565 mono_defaults.corlib, "System", "Exception");
1566 g_assert (mono_defaults.exception_class != 0);
1568 mono_defaults.threadabortexception_class = mono_class_from_name (
1569 mono_defaults.corlib, "System.Threading", "ThreadAbortException");
1570 g_assert (mono_defaults.threadabortexception_class != 0);
1572 mono_defaults.thread_class = mono_class_from_name (
1573 mono_defaults.corlib, "System.Threading", "Thread");
1574 g_assert (mono_defaults.thread_class != 0);
1576 mono_defaults.internal_thread_class = mono_class_from_name (
1577 mono_defaults.corlib, "System.Threading", "InternalThread");
1578 if (!mono_defaults.internal_thread_class) {
1579 /* This can happen with an old mscorlib */
1580 fprintf (stderr, "Corlib too old for this runtime.\n");
1581 fprintf (stderr, "Loaded from: %s\n",
1582 mono_defaults.corlib? mono_image_get_filename (mono_defaults.corlib): "unknown");
1586 mono_defaults.appdomain_class = mono_class_from_name (
1587 mono_defaults.corlib, "System", "AppDomain");
1588 g_assert (mono_defaults.appdomain_class != 0);
1590 #ifndef DISABLE_REMOTING
1591 mono_defaults.transparent_proxy_class = mono_class_from_name (
1592 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "TransparentProxy");
1593 g_assert (mono_defaults.transparent_proxy_class != 0);
1595 mono_defaults.real_proxy_class = mono_class_from_name (
1596 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "RealProxy");
1597 g_assert (mono_defaults.real_proxy_class != 0);
1599 mono_defaults.marshalbyrefobject_class = mono_class_from_name (
1600 mono_defaults.corlib, "System", "MarshalByRefObject");
1601 g_assert (mono_defaults.marshalbyrefobject_class != 0);
1603 mono_defaults.iremotingtypeinfo_class = mono_class_from_name (
1604 mono_defaults.corlib, "System.Runtime.Remoting", "IRemotingTypeInfo");
1605 g_assert (mono_defaults.iremotingtypeinfo_class != 0);
1608 mono_defaults.mono_method_message_class = mono_class_from_name (
1609 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", "MonoMethodMessage");
1610 g_assert (mono_defaults.mono_method_message_class != 0);
1612 mono_defaults.field_info_class = mono_class_from_name (
1613 mono_defaults.corlib, "System.Reflection", "FieldInfo");
1614 g_assert (mono_defaults.field_info_class != 0);
1616 mono_defaults.method_info_class = mono_class_from_name (
1617 mono_defaults.corlib, "System.Reflection", "MethodInfo");
1618 g_assert (mono_defaults.method_info_class != 0);
1620 mono_defaults.stringbuilder_class = mono_class_from_name (
1621 mono_defaults.corlib, "System.Text", "StringBuilder");
1622 g_assert (mono_defaults.stringbuilder_class != 0);
1624 mono_defaults.math_class = mono_class_from_name (
1625 mono_defaults.corlib, "System", "Math");
1626 g_assert (mono_defaults.math_class != 0);
1628 mono_defaults.stack_frame_class = mono_class_from_name (
1629 mono_defaults.corlib, "System.Diagnostics", "StackFrame");
1630 g_assert (mono_defaults.stack_frame_class != 0);
1632 mono_defaults.stack_trace_class = mono_class_from_name (
1633 mono_defaults.corlib, "System.Diagnostics", "StackTrace");
1634 g_assert (mono_defaults.stack_trace_class != 0);
1636 mono_defaults.marshal_class = mono_class_from_name (
1637 mono_defaults.corlib, "System.Runtime.InteropServices", "Marshal");
1638 g_assert (mono_defaults.marshal_class != 0);
1640 mono_defaults.typed_reference_class = mono_class_from_name (
1641 mono_defaults.corlib, "System", "TypedReference");
1642 g_assert (mono_defaults.typed_reference_class != 0);
1644 mono_defaults.argumenthandle_class = mono_class_from_name (
1645 mono_defaults.corlib, "System", "RuntimeArgumentHandle");
1646 g_assert (mono_defaults.argumenthandle_class != 0);
1648 mono_defaults.monitor_class = mono_class_from_name (
1649 mono_defaults.corlib, "System.Threading", "Monitor");
1650 g_assert (mono_defaults.monitor_class != 0);
1652 mono_defaults.runtimesecurityframe_class = mono_class_from_name (
1653 mono_defaults.corlib, "System.Security", "RuntimeSecurityFrame");
1655 mono_defaults.executioncontext_class = mono_class_from_name (
1656 mono_defaults.corlib, "System.Threading", "ExecutionContext");
1658 mono_defaults.internals_visible_class = mono_class_from_name (
1659 mono_defaults.corlib, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute");
1661 mono_defaults.critical_finalizer_object = mono_class_from_name (
1662 mono_defaults.corlib, "System.Runtime.ConstrainedExecution", "CriticalFinalizerObject");
1665 * mscorlib needs a little help, only now it can load its friends list (after we have
1666 * loaded the InternalsVisibleToAttribute), load it now
1668 mono_assembly_load_friends (ass);
1670 mono_defaults.safehandle_class = mono_class_from_name (
1671 mono_defaults.corlib, "System.Runtime.InteropServices", "SafeHandle");
1673 mono_defaults.handleref_class = mono_class_from_name (
1674 mono_defaults.corlib, "System.Runtime.InteropServices", "HandleRef");
1676 mono_defaults.attribute_class = mono_class_from_name (
1677 mono_defaults.corlib, "System", "Attribute");
1679 mono_defaults.customattribute_data_class = mono_class_from_name (
1680 mono_defaults.corlib, "System.Reflection", "CustomAttributeData");
1682 /* these are initialized lazily when COM features are used */
1684 mono_class_init (mono_defaults.array_class);
1685 mono_defaults.generic_nullable_class = mono_class_from_name (
1686 mono_defaults.corlib, "System", "Nullable`1");
1687 mono_defaults.generic_ilist_class = mono_class_from_name (
1688 mono_defaults.corlib, "System.Collections.Generic", "IList`1");
1689 mono_defaults.generic_ireadonlylist_class = mono_class_from_name (
1690 mono_defaults.corlib, "System.Collections.Generic", "IReadOnlyList`1");
1692 domain->friendly_name = g_path_get_basename (filename);
1694 _mono_debug_init_corlib (domain);
1702 * Creates the initial application domain and initializes the mono_defaults
1704 * This function is guaranteed to not run any IL code.
1705 * The runtime is initialized using the default runtime version.
1707 * Returns: the initial domain.
1710 mono_init (const char *domain_name)
1712 return mono_init_internal (domain_name, NULL, DEFAULT_RUNTIME_VERSION);
1716 * mono_init_from_assembly:
1717 * @domain_name: name to give to the initial domain
1718 * @filename: filename to load on startup
1720 * Used by the runtime, users should use mono_jit_init instead.
1722 * Creates the initial application domain and initializes the mono_defaults
1724 * This function is guaranteed to not run any IL code.
1725 * The runtime is initialized using the runtime version required by the
1726 * provided executable. The version is determined by looking at the exe
1727 * configuration file and the version PE field)
1729 * Returns: the initial domain.
1732 mono_init_from_assembly (const char *domain_name, const char *filename)
1734 return mono_init_internal (domain_name, filename, NULL);
1738 * mono_init_version:
1740 * Used by the runtime, users should use mono_jit_init instead.
1742 * Creates the initial application domain and initializes the mono_defaults
1745 * This function is guaranteed to not run any IL code.
1746 * The runtime is initialized using the provided rutime version.
1748 * Returns: the initial domain.
1751 mono_init_version (const char *domain_name, const char *version)
1753 return mono_init_internal (domain_name, NULL, version);
1759 * Cleans up all metadata modules.
1764 mono_close_exe_image ();
1766 mono_defaults.corlib = NULL;
1768 mono_config_cleanup ();
1769 mono_loader_cleanup ();
1770 mono_classes_cleanup ();
1771 mono_assemblies_cleanup ();
1772 mono_images_cleanup ();
1773 mono_debug_cleanup ();
1774 mono_metadata_cleanup ();
1776 mono_native_tls_free (appdomain_thread_id);
1777 DeleteCriticalSection (&appdomains_mutex);
1785 mono_close_exe_image (void)
1788 mono_image_close (exe_image);
1792 * mono_get_root_domain:
1794 * The root AppDomain is the initial domain created by the runtime when it is
1795 * initialized. Programs execute on this AppDomain, but can create new ones
1796 * later. Currently there is no unmanaged API to create new AppDomains, this
1797 * must be done from managed code.
1799 * Returns: the root appdomain, to obtain the current domain, use mono_domain_get ()
1802 mono_get_root_domain (void)
1804 return mono_root_domain;
1810 * Returns: the current domain, to obtain the root domain use
1811 * mono_get_root_domain().
1816 return GET_APPDOMAIN ();
1820 mono_domain_unset (void)
1822 SET_APPDOMAIN (NULL);
1826 mono_domain_set_internal_with_options (MonoDomain *domain, gboolean migrate_exception)
1828 MonoInternalThread *thread;
1830 if (mono_domain_get () == domain)
1833 SET_APPDOMAIN (domain);
1834 SET_APPCONTEXT (domain->default_context);
1836 if (migrate_exception) {
1837 thread = mono_thread_internal_current ();
1838 if (!thread->abort_exc)
1841 g_assert (thread->abort_exc->object.vtable->domain != domain);
1842 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
1843 g_assert (thread->abort_exc->object.vtable->domain == domain);
1848 * mono_domain_set_internal:
1849 * @domain: the new domain
1851 * Sets the current domain to @domain.
1854 mono_domain_set_internal (MonoDomain *domain)
1856 mono_domain_set_internal_with_options (domain, TRUE);
1860 mono_domain_foreach (MonoDomainFunc func, gpointer user_data)
1866 * Create a copy of the data to avoid calling the user callback
1867 * inside the lock because that could lead to deadlocks.
1868 * We can do this because this function is not perf. critical.
1870 mono_appdomains_lock ();
1871 size = appdomain_list_size;
1872 copy = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1873 memcpy (copy, appdomains_list, appdomain_list_size * sizeof (void*));
1874 mono_appdomains_unlock ();
1876 for (i = 0; i < size; ++i) {
1878 func (copy [i], user_data);
1881 mono_gc_free_fixed (copy);
1885 * mono_domain_assembly_open:
1886 * @domain: the application domain
1887 * @name: file name of the assembly
1889 * fixme: maybe we should integrate this with mono_assembly_open ??
1892 mono_domain_assembly_open (MonoDomain *domain, const char *name)
1894 MonoDomain *current;
1898 mono_domain_assemblies_lock (domain);
1899 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1901 if (strcmp (name, ass->aname.name) == 0) {
1902 mono_domain_assemblies_unlock (domain);
1906 mono_domain_assemblies_unlock (domain);
1908 if (domain != mono_domain_get ()) {
1909 current = mono_domain_get ();
1911 mono_domain_set (domain, FALSE);
1912 ass = mono_assembly_open (name, NULL);
1913 mono_domain_set (current, FALSE);
1915 ass = mono_assembly_open (name, NULL);
1922 unregister_vtable_reflection_type (MonoVTable *vtable)
1924 MonoObject *type = vtable->type;
1926 if (type->vtable->klass != mono_defaults.monotype_class)
1927 MONO_GC_UNREGISTER_ROOT_IF_MOVING (vtable->type);
1931 mono_domain_free (MonoDomain *domain, gboolean force)
1933 int code_size, code_alloc;
1937 if ((domain == mono_root_domain) && !force) {
1938 g_warning ("cant unload root domain");
1942 if (mono_dont_free_domains)
1945 mono_profiler_appdomain_event (domain, MONO_PROFILE_START_UNLOAD);
1947 mono_debug_domain_unload (domain);
1949 mono_appdomains_lock ();
1950 appdomains_list [domain->domain_id] = NULL;
1951 mono_appdomains_unlock ();
1953 /* must do this early as it accesses fields and types */
1954 if (domain->special_static_fields) {
1955 mono_alloc_special_static_data_free (domain->special_static_fields);
1956 g_hash_table_destroy (domain->special_static_fields);
1957 domain->special_static_fields = NULL;
1961 * We must destroy all these hash tables here because they
1962 * contain references to managed objects belonging to the
1963 * domain. Once we let the GC clear the domain there must be
1964 * no more such references, or we'll crash if a collection
1967 mono_g_hash_table_destroy (domain->ldstr_table);
1968 domain->ldstr_table = NULL;
1970 mono_g_hash_table_destroy (domain->env);
1973 if (domain->tlsrec_list) {
1974 mono_thread_destroy_domain_tls (domain);
1975 domain->tlsrec_list = NULL;
1978 mono_reflection_cleanup_domain (domain);
1980 /* This must be done before type_hash is freed */
1981 if (domain->class_vtable_array) {
1983 for (i = 0; i < domain->class_vtable_array->len; ++i)
1984 unregister_vtable_reflection_type (g_ptr_array_index (domain->class_vtable_array, i));
1987 if (domain->type_hash) {
1988 mono_g_hash_table_destroy (domain->type_hash);
1989 domain->type_hash = NULL;
1991 if (domain->type_init_exception_hash) {
1992 mono_g_hash_table_destroy (domain->type_init_exception_hash);
1993 domain->type_init_exception_hash = NULL;
1996 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1997 MonoAssembly *ass = tmp->data;
1998 mono_assembly_release_gc_roots (ass);
2001 /* Have to zero out reference fields since they will be invalidated by the clear_domain () call below */
2002 for (p = (gpointer*)&domain->MONO_DOMAIN_FIRST_OBJECT; p < (gpointer*)&domain->MONO_DOMAIN_FIRST_GC_TRACKED; ++p)
2005 /* This needs to be done before closing assemblies */
2006 mono_gc_clear_domain (domain);
2008 /* Close dynamic assemblies first, since they have no ref count */
2009 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2010 MonoAssembly *ass = tmp->data;
2011 if (!ass->image || !ass->image->dynamic)
2013 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);
2014 if (!mono_assembly_close_except_image_pools (ass))
2018 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2019 MonoAssembly *ass = tmp->data;
2022 if (!ass->image || ass->image->dynamic)
2024 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);
2025 if (!mono_assembly_close_except_image_pools (ass))
2029 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2030 MonoAssembly *ass = tmp->data;
2032 mono_assembly_close_finish (ass);
2034 g_slist_free (domain->domain_assemblies);
2035 domain->domain_assemblies = NULL;
2038 * Send this after the assemblies have been unloaded and the domain is still in a
2041 mono_profiler_appdomain_event (domain, MONO_PROFILE_END_UNLOAD);
2043 if (free_domain_hook)
2044 free_domain_hook (domain);
2046 /* FIXME: free delegate_hash_table when it's used */
2047 if (domain->search_path) {
2048 g_strfreev (domain->search_path);
2049 domain->search_path = NULL;
2051 domain->create_proxy_for_type_method = NULL;
2052 domain->private_invoke_method = NULL;
2053 domain->default_context = NULL;
2054 domain->out_of_memory_ex = NULL;
2055 domain->null_reference_ex = NULL;
2056 domain->stack_overflow_ex = NULL;
2057 domain->ephemeron_tombstone = NULL;
2058 domain->entry_assembly = NULL;
2060 g_free (domain->friendly_name);
2061 domain->friendly_name = NULL;
2062 g_ptr_array_free (domain->class_vtable_array, TRUE);
2063 domain->class_vtable_array = NULL;
2064 g_hash_table_destroy (domain->proxy_vtable_hash);
2065 domain->proxy_vtable_hash = NULL;
2066 if (domain->static_data_array) {
2067 mono_gc_free_fixed (domain->static_data_array);
2068 domain->static_data_array = NULL;
2070 mono_internal_hash_table_destroy (&domain->jit_code_hash);
2073 * There might still be jit info tables of this domain which
2074 * are not freed. Since the domain cannot be in use anymore,
2075 * this will free them.
2077 mono_thread_hazardous_try_free_all ();
2078 if (domain->aot_modules)
2079 jit_info_table_free (domain->aot_modules);
2080 g_assert (domain->num_jit_info_tables == 1);
2081 jit_info_table_free (domain->jit_info_table);
2082 domain->jit_info_table = NULL;
2083 g_assert (!domain->jit_info_free_queue);
2085 /* collect statistics */
2086 code_alloc = mono_code_manager_size (domain->code_mp, &code_size);
2087 total_domain_code_alloc += code_alloc;
2088 max_domain_code_alloc = MAX (max_domain_code_alloc, code_alloc);
2089 max_domain_code_size = MAX (max_domain_code_size, code_size);
2091 #ifdef DEBUG_DOMAIN_UNLOAD
2092 mono_mempool_invalidate (domain->mp);
2093 mono_code_manager_invalidate (domain->code_mp);
2095 #ifndef DISABLE_PERFCOUNTERS
2096 mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (domain->mp);
2098 mono_mempool_destroy (domain->mp);
2100 mono_code_manager_destroy (domain->code_mp);
2101 domain->code_mp = NULL;
2103 lock_free_mempool_free (domain->lock_free_mp);
2104 domain->lock_free_mp = NULL;
2106 g_hash_table_destroy (domain->finalizable_objects_hash);
2107 domain->finalizable_objects_hash = NULL;
2108 if (domain->method_rgctx_hash) {
2109 g_hash_table_destroy (domain->method_rgctx_hash);
2110 domain->method_rgctx_hash = NULL;
2112 if (domain->generic_virtual_cases) {
2113 g_hash_table_destroy (domain->generic_virtual_cases);
2114 domain->generic_virtual_cases = NULL;
2116 if (domain->generic_virtual_thunks) {
2117 g_hash_table_destroy (domain->generic_virtual_thunks);
2118 domain->generic_virtual_thunks = NULL;
2120 if (domain->ftnptrs_hash) {
2121 g_hash_table_destroy (domain->ftnptrs_hash);
2122 domain->ftnptrs_hash = NULL;
2125 DeleteCriticalSection (&domain->finalizable_objects_hash_lock);
2126 DeleteCriticalSection (&domain->assemblies_lock);
2127 DeleteCriticalSection (&domain->jit_code_hash_lock);
2128 DeleteCriticalSection (&domain->lock);
2129 domain->setup = NULL;
2131 mono_gc_deregister_root ((char*)&(domain->MONO_DOMAIN_FIRST_GC_TRACKED));
2133 /* FIXME: anything else required ? */
2135 mono_gc_free_fixed (domain);
2137 #ifndef DISABLE_PERFCOUNTERS
2138 mono_perfcounters->loader_appdomains--;
2141 if (domain == mono_root_domain)
2142 mono_root_domain = NULL;
2146 * mono_domain_get_id:
2149 * Returns: the a domain for a specific domain id.
2152 mono_domain_get_by_id (gint32 domainid)
2154 MonoDomain * domain;
2156 mono_appdomains_lock ();
2157 if (domainid < appdomain_list_size)
2158 domain = appdomains_list [domainid];
2161 mono_appdomains_unlock ();
2167 mono_domain_get_id (MonoDomain *domain)
2169 return domain->domain_id;
2173 * mono_domain_alloc:
2175 * LOCKING: Acquires the domain lock.
2178 mono_domain_alloc (MonoDomain *domain, guint size)
2182 mono_domain_lock (domain);
2183 #ifndef DISABLE_PERFCOUNTERS
2184 mono_perfcounters->loader_bytes += size;
2186 res = mono_mempool_alloc (domain->mp, size);
2187 mono_domain_unlock (domain);
2193 * mono_domain_alloc0:
2195 * LOCKING: Acquires the domain lock.
2198 mono_domain_alloc0 (MonoDomain *domain, guint size)
2202 mono_domain_lock (domain);
2203 #ifndef DISABLE_PERFCOUNTERS
2204 mono_perfcounters->loader_bytes += size;
2206 res = mono_mempool_alloc0 (domain->mp, size);
2207 mono_domain_unlock (domain);
2213 mono_domain_alloc0_lock_free (MonoDomain *domain, guint size)
2215 return lock_free_mempool_alloc0 (domain->lock_free_mp, size);
2219 * mono_domain_code_reserve:
2221 * LOCKING: Acquires the domain lock.
2224 mono_domain_code_reserve (MonoDomain *domain, int size)
2228 mono_domain_lock (domain);
2229 res = mono_code_manager_reserve (domain->code_mp, size);
2230 mono_domain_unlock (domain);
2236 * mono_domain_code_reserve_align:
2238 * LOCKING: Acquires the domain lock.
2241 mono_domain_code_reserve_align (MonoDomain *domain, int size, int alignment)
2245 mono_domain_lock (domain);
2246 res = mono_code_manager_reserve_align (domain->code_mp, size, alignment);
2247 mono_domain_unlock (domain);
2253 * mono_domain_code_commit:
2255 * LOCKING: Acquires the domain lock.
2258 mono_domain_code_commit (MonoDomain *domain, void *data, int size, int newsize)
2260 mono_domain_lock (domain);
2261 mono_code_manager_commit (domain->code_mp, data, size, newsize);
2262 mono_domain_unlock (domain);
2265 #if defined(__native_client_codegen__) && defined(__native_client__)
2267 * Given the temporary buffer (allocated by mono_domain_code_reserve) into which
2268 * we are generating code, return a pointer to the destination in the dynamic
2269 * code segment into which the code will be copied when mono_domain_code_commit
2271 * LOCKING: Acquires the domain lock.
2274 nacl_domain_get_code_dest (MonoDomain *domain, void *data)
2277 mono_domain_lock (domain);
2278 dest = nacl_code_manager_get_code_dest (domain->code_mp, data);
2279 mono_domain_unlock (domain);
2284 * Convenience function which calls mono_domain_code_commit to validate and copy
2285 * the code. The caller sets *buf_base and *buf_size to the start and size of
2286 * the buffer (allocated by mono_domain_code_reserve), and *code_end to the byte
2287 * after the last instruction byte. On return, *buf_base will point to the start
2288 * of the copied in the code segment, and *code_end will point after the end of
2292 nacl_domain_code_validate (MonoDomain *domain, guint8 **buf_base, int buf_size, guint8 **code_end)
2294 guint8 *tmp = nacl_domain_get_code_dest (domain, *buf_base);
2295 mono_domain_code_commit (domain, *buf_base, buf_size, *code_end - *buf_base);
2296 *code_end = tmp + (*code_end - *buf_base);
2302 /* no-op versions of Native Client functions */
2305 nacl_domain_get_code_dest (MonoDomain *domain, void *data)
2311 nacl_domain_code_validate (MonoDomain *domain, guint8 **buf_base, int buf_size, guint8 **code_end)
2318 * mono_domain_code_foreach:
2319 * Iterate over the code thunks of the code manager of @domain.
2321 * The @func callback MUST not take any locks. If it really needs to, it must respect
2322 * the locking rules of the runtime: http://www.mono-project.com/Mono:Runtime:Documentation:ThreadSafety
2323 * LOCKING: Acquires the domain lock.
2327 mono_domain_code_foreach (MonoDomain *domain, MonoCodeManagerFunc func, void *user_data)
2329 mono_domain_lock (domain);
2330 mono_code_manager_foreach (domain->code_mp, func, user_data);
2331 mono_domain_unlock (domain);
2336 mono_context_set (MonoAppContext * new_context)
2338 SET_APPCONTEXT (new_context);
2342 mono_context_get (void)
2344 return GET_APPCONTEXT ();
2347 /* LOCKING: the caller holds the lock for this domain */
2349 mono_domain_add_class_static_data (MonoDomain *domain, MonoClass *klass, gpointer data, guint32 *bitmap)
2351 /* The first entry in the array is the index of the next free slot
2352 * and the total size of the array
2355 if (domain->static_data_array) {
2356 int size = GPOINTER_TO_INT (domain->static_data_array [1]);
2357 next = GPOINTER_TO_INT (domain->static_data_array [0]);
2359 /* 'data' is allocated by alloc_fixed */
2360 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * (size * 2), MONO_GC_ROOT_DESCR_FOR_FIXED (size * 2));
2361 mono_gc_memmove_aligned (new_array, domain->static_data_array, sizeof (gpointer) * size);
2363 new_array [1] = GINT_TO_POINTER (size);
2364 mono_gc_free_fixed (domain->static_data_array);
2365 domain->static_data_array = new_array;
2369 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * size, MONO_GC_ROOT_DESCR_FOR_FIXED (size));
2371 new_array [0] = GINT_TO_POINTER (next);
2372 new_array [1] = GINT_TO_POINTER (size);
2373 domain->static_data_array = new_array;
2375 domain->static_data_array [next++] = data;
2376 domain->static_data_array [0] = GINT_TO_POINTER (next);
2380 mono_get_corlib (void)
2382 return mono_defaults.corlib;
2386 mono_get_object_class (void)
2388 return mono_defaults.object_class;
2392 mono_get_byte_class (void)
2394 return mono_defaults.byte_class;
2398 mono_get_void_class (void)
2400 return mono_defaults.void_class;
2404 mono_get_boolean_class (void)
2406 return mono_defaults.boolean_class;
2410 mono_get_sbyte_class (void)
2412 return mono_defaults.sbyte_class;
2416 mono_get_int16_class (void)
2418 return mono_defaults.int16_class;
2422 mono_get_uint16_class (void)
2424 return mono_defaults.uint16_class;
2428 mono_get_int32_class (void)
2430 return mono_defaults.int32_class;
2434 mono_get_uint32_class (void)
2436 return mono_defaults.uint32_class;
2440 mono_get_intptr_class (void)
2442 return mono_defaults.int_class;
2446 mono_get_uintptr_class (void)
2448 return mono_defaults.uint_class;
2452 mono_get_int64_class (void)
2454 return mono_defaults.int64_class;
2458 mono_get_uint64_class (void)
2460 return mono_defaults.uint64_class;
2464 mono_get_single_class (void)
2466 return mono_defaults.single_class;
2470 mono_get_double_class (void)
2472 return mono_defaults.double_class;
2476 mono_get_char_class (void)
2478 return mono_defaults.char_class;
2482 mono_get_string_class (void)
2484 return mono_defaults.string_class;
2488 mono_get_enum_class (void)
2490 return mono_defaults.enum_class;
2494 mono_get_array_class (void)
2496 return mono_defaults.array_class;
2500 mono_get_thread_class (void)
2502 return mono_defaults.thread_class;
2506 mono_get_exception_class (void)
2508 return mono_defaults.exception_class;
2512 static char* get_attribute_value (const gchar **attribute_names,
2513 const gchar **attribute_values,
2514 const char *att_name)
2517 for (n=0; attribute_names[n] != NULL; n++) {
2518 if (strcmp (attribute_names[n], att_name) == 0)
2519 return g_strdup (attribute_values[n]);
2524 static void start_element (GMarkupParseContext *context,
2525 const gchar *element_name,
2526 const gchar **attribute_names,
2527 const gchar **attribute_values,
2531 AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2533 if (strcmp (element_name, "configuration") == 0) {
2534 app_config->configuration_count++;
2537 if (strcmp (element_name, "startup") == 0) {
2538 app_config->startup_count++;
2542 if (app_config->configuration_count != 1 || app_config->startup_count != 1)
2545 if (strcmp (element_name, "requiredRuntime") == 0) {
2546 app_config->required_runtime = get_attribute_value (attribute_names, attribute_values, "version");
2547 } else if (strcmp (element_name, "supportedRuntime") == 0) {
2548 char *version = get_attribute_value (attribute_names, attribute_values, "version");
2549 app_config->supported_runtimes = g_slist_append (app_config->supported_runtimes, version);
2553 static void end_element (GMarkupParseContext *context,
2554 const gchar *element_name,
2558 AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2560 if (strcmp (element_name, "configuration") == 0) {
2561 app_config->configuration_count--;
2562 } else if (strcmp (element_name, "startup") == 0) {
2563 app_config->startup_count--;
2567 static const GMarkupParser
2576 static AppConfigInfo *
2577 app_config_parse (const char *exe_filename)
2579 AppConfigInfo *app_config;
2580 GMarkupParseContext *context;
2583 const char *bundled_config;
2584 char *config_filename;
2586 bundled_config = mono_config_string_for_assembly_file (exe_filename);
2588 if (bundled_config) {
2589 text = g_strdup (bundled_config);
2590 len = strlen (text);
2592 config_filename = g_strconcat (exe_filename, ".config", NULL);
2594 if (!g_file_get_contents (config_filename, &text, &len, NULL)) {
2595 g_free (config_filename);
2598 g_free (config_filename);
2601 app_config = g_new0 (AppConfigInfo, 1);
2603 context = g_markup_parse_context_new (&mono_parser, 0, app_config, NULL);
2604 if (g_markup_parse_context_parse (context, text, len, NULL)) {
2605 g_markup_parse_context_end_parse (context, NULL);
2607 g_markup_parse_context_free (context);
2613 app_config_free (AppConfigInfo* app_config)
2616 GSList *list = app_config->supported_runtimes;
2617 while (list != NULL) {
2618 rt = (char*)list->data;
2620 list = g_slist_next (list);
2622 g_slist_free (app_config->supported_runtimes);
2623 g_free (app_config->required_runtime);
2624 g_free (app_config);
2628 static const MonoRuntimeInfo*
2629 get_runtime_by_version (const char *version)
2632 int max = G_N_ELEMENTS (supported_runtimes);
2638 for (n=0; n<max; n++) {
2639 if (strcmp (version, supported_runtimes[n].runtime_version) == 0)
2640 return &supported_runtimes[n];
2643 vlen = strlen (version);
2644 if (vlen >= 4 && version [1] - '0' >= 4) {
2645 for (n=0; n<max; n++) {
2646 if (strncmp (version, supported_runtimes[n].runtime_version, 4) == 0)
2647 return &supported_runtimes[n];
2655 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes)
2657 AppConfigInfo* app_config;
2659 const MonoRuntimeInfo* runtime = NULL;
2660 MonoImage *image = NULL;
2662 app_config = app_config_parse (exe_file);
2664 if (app_config != NULL) {
2665 /* Check supportedRuntime elements, if none is supported, fail.
2666 * If there are no such elements, look for a requiredRuntime element.
2668 if (app_config->supported_runtimes != NULL) {
2670 GSList *list = app_config->supported_runtimes;
2671 while (list != NULL) {
2672 version = (char*) list->data;
2673 runtime = get_runtime_by_version (version);
2674 if (runtime != NULL)
2675 runtimes [n++] = runtime;
2676 list = g_slist_next (list);
2678 runtimes [n] = NULL;
2679 app_config_free (app_config);
2683 /* Check the requiredRuntime element. This is for 1.0 apps only. */
2684 if (app_config->required_runtime != NULL) {
2685 runtimes [0] = get_runtime_by_version (app_config->required_runtime);
2686 runtimes [1] = NULL;
2687 app_config_free (app_config);
2690 app_config_free (app_config);
2693 /* Look for a runtime with the exact version */
2694 image = mono_assembly_open_from_bundle (exe_file, NULL, FALSE);
2697 image = mono_image_open (exe_file, NULL);
2699 if (image == NULL) {
2700 /* The image is wrong or the file was not found. In this case return
2701 * a default runtime and leave to the initialization method the work of
2702 * reporting the error.
2704 runtimes [0] = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
2705 runtimes [1] = NULL;
2711 runtimes [0] = get_runtime_by_version (image->version);
2712 runtimes [1] = NULL;
2717 * mono_get_runtime_info:
2719 * Returns: the version of the current runtime instance.
2721 const MonoRuntimeInfo*
2722 mono_get_runtime_info (void)
2724 return current_runtime;
2728 mono_debugger_check_runtime_version (const char *filename)
2730 const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
2731 const MonoRuntimeInfo *rinfo;
2734 get_runtimes_from_exe (filename, &image, runtimes);
2735 rinfo = runtimes [0];
2738 return g_strdup_printf ("Cannot get runtime version from assembly `%s'", filename);
2740 if (rinfo != current_runtime)
2741 return g_strdup_printf ("The Mono Debugger is currently using the `%s' runtime, but "
2742 "the assembly `%s' requires version `%s'", current_runtime->runtime_version,
2743 filename, rinfo->runtime_version);
2749 * mono_framework_version:
2751 * Return the major version of the framework curently executing.
2754 mono_framework_version (void)
2756 return current_runtime->framework_version [0] - '0';