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/metadata/object.h>
29 #include <mono/metadata/object-internals.h>
30 #include <mono/metadata/domain-internals.h>
31 #include <mono/metadata/class-internals.h>
32 #include <mono/metadata/assembly.h>
33 #include <mono/metadata/exception.h>
34 #include <mono/metadata/metadata-internals.h>
35 #include <mono/metadata/gc-internal.h>
36 #include <mono/metadata/appdomain.h>
37 #include <mono/metadata/mono-debug-debugger.h>
38 #include <mono/metadata/mono-config.h>
39 #include <mono/metadata/threads-types.h>
40 #include <mono/metadata/runtime.h>
41 #include <metadata/threads.h>
42 #include <metadata/profiler-private.h>
43 #include <mono/metadata/coree.h>
45 /* #define DEBUG_DOMAIN_UNLOAD */
47 /* we need to use both the Tls* functions and __thread because
48 * some archs may generate faster jit code with one meachanism
49 * or the other (we used to do it because tls slots were GC-tracked,
50 * but we can't depend on this).
52 static MonoNativeTlsKey appdomain_thread_id;
54 #ifdef MONO_HAVE_FAST_TLS
56 MONO_FAST_TLS_DECLARE(tls_appdomain);
58 #define GET_APPDOMAIN() ((MonoDomain*)MONO_FAST_TLS_GET(tls_appdomain))
60 #define SET_APPDOMAIN(x) do { \
61 MONO_FAST_TLS_SET (tls_appdomain,x); \
62 mono_native_tls_set_value (appdomain_thread_id, x); \
63 mono_gc_set_current_thread_appdomain (x); \
66 #else /* !MONO_HAVE_FAST_TLS */
68 #define GET_APPDOMAIN() ((MonoDomain *)mono_native_tls_get_value (appdomain_thread_id))
69 #define SET_APPDOMAIN(x) do { \
70 mono_native_tls_set_value (appdomain_thread_id, x); \
71 mono_gc_set_current_thread_appdomain (x); \
76 #define GET_APPCONTEXT() (mono_thread_internal_current ()->current_appcontext)
77 #define SET_APPCONTEXT(x) MONO_OBJECT_SETREF (mono_thread_internal_current (), current_appcontext, (x))
79 static guint16 appdomain_list_size = 0;
80 static guint16 appdomain_next = 0;
81 static MonoDomain **appdomains_list = NULL;
82 static MonoImage *exe_image;
84 gboolean mono_dont_free_domains;
86 #define mono_appdomains_lock() EnterCriticalSection (&appdomains_mutex)
87 #define mono_appdomains_unlock() LeaveCriticalSection (&appdomains_mutex)
88 static CRITICAL_SECTION appdomains_mutex;
90 static MonoDomain *mono_root_domain = NULL;
93 static int max_domain_code_size = 0;
94 static int max_domain_code_alloc = 0;
95 static int total_domain_code_alloc = 0;
97 /* AppConfigInfo: Information about runtime versions supported by an
101 GSList *supported_runtimes;
102 char *required_runtime;
103 int configuration_count;
107 static const MonoRuntimeInfo *current_runtime = NULL;
109 static MonoJitInfoFindInAot jit_info_find_in_aot_func = NULL;
111 /* This is the list of runtime versions supported by this JIT.
113 static const MonoRuntimeInfo supported_runtimes[] = {
114 {"v2.0.50215","2.0", { {2,0,0,0}, { 8,0,0,0}, {3,5,0,0}, {3,0,0,0} } },
115 {"v2.0.50727","2.0", { {2,0,0,0}, { 8,0,0,0}, {3,5,0,0}, {3,0,0,0} } },
116 {"v4.0.30319","4.5", { {4,0,0,0}, {10,0,0,0}, {4,0,0,0}, {4,0,0,0} } },
117 {"v4.0.30128","4.0", { {4,0,0,0}, {10,0,0,0}, {4,0,0,0}, {4,0,0,0} } },
118 {"v4.0.20506","4.0", { {4,0,0,0}, {10,0,0,0}, {4,0,0,0}, {4,0,0,0} } },
119 {"moonlight", "2.1", { {2,0,5,0}, { 9,0,0,0}, {3,5,0,0}, {3,0,0,0} } },
123 /* The stable runtime version */
124 #define DEFAULT_RUNTIME_VERSION "v2.0.50727"
126 /* Callbacks installed by the JIT */
127 static MonoCreateDomainFunc create_domain_hook;
128 static MonoFreeDomainFunc free_domain_hook;
130 /* This is intentionally not in the header file, so people don't misuse it. */
131 extern void _mono_debug_init_corlib (MonoDomain *domain);
134 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes);
136 static const MonoRuntimeInfo*
137 get_runtime_by_version (const char *version);
140 mono_domain_get_tls_key (void)
142 return appdomain_thread_id;
146 mono_domain_get_tls_offset (void)
149 MONO_THREAD_VAR_OFFSET (tls_appdomain, offset);
150 /* __asm ("jmp 1f; .section writetext, \"awx\"; 1: movl $tls_appdomain@ntpoff, %0; jmp 2f; .previous; 2:"
155 #define JIT_INFO_TABLE_FILL_RATIO_NOM 3
156 #define JIT_INFO_TABLE_FILL_RATIO_DENOM 4
157 #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)
159 #define JIT_INFO_TABLE_LOW_WATERMARK(n) ((n) / 2)
160 #define JIT_INFO_TABLE_HIGH_WATERMARK(n) ((n) * 5 / 6)
162 #define JIT_INFO_TOMBSTONE_MARKER ((MonoMethod*)NULL)
163 #define IS_JIT_INFO_TOMBSTONE(ji) ((ji)->d.method == JIT_INFO_TOMBSTONE_MARKER)
165 #define JIT_INFO_TABLE_HAZARD_INDEX 0
166 #define JIT_INFO_HAZARD_INDEX 1
169 jit_info_table_num_elements (MonoJitInfoTable *table)
172 int num_elements = 0;
174 for (i = 0; i < table->num_chunks; ++i) {
175 MonoJitInfoTableChunk *chunk = table->chunks [i];
176 int chunk_num_elements = chunk->num_elements;
179 for (j = 0; j < chunk_num_elements; ++j) {
180 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j]))
188 static MonoJitInfoTableChunk*
189 jit_info_table_new_chunk (void)
191 MonoJitInfoTableChunk *chunk = g_new0 (MonoJitInfoTableChunk, 1);
197 static MonoJitInfoTable *
198 jit_info_table_new (MonoDomain *domain)
200 MonoJitInfoTable *table = g_malloc0 (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*));
202 table->domain = domain;
203 table->num_chunks = 1;
204 table->chunks [0] = jit_info_table_new_chunk ();
210 jit_info_table_free (MonoJitInfoTable *table)
213 int num_chunks = table->num_chunks;
214 MonoDomain *domain = table->domain;
216 mono_domain_lock (domain);
218 table->domain->num_jit_info_tables--;
219 if (table->domain->num_jit_info_tables <= 1) {
222 for (list = table->domain->jit_info_free_queue; list; list = list->next)
225 g_slist_free (table->domain->jit_info_free_queue);
226 table->domain->jit_info_free_queue = NULL;
229 /* At this point we assume that there are no other threads
230 still accessing the table, so we don't have to worry about
231 hazardous pointers. */
233 for (i = 0; i < num_chunks; ++i) {
234 MonoJitInfoTableChunk *chunk = table->chunks [i];
238 if (--chunk->refcount > 0)
241 num_elements = chunk->num_elements;
242 for (j = 0; j < num_elements; ++j) {
243 MonoJitInfo *ji = chunk->data [j];
245 if (IS_JIT_INFO_TOMBSTONE (ji))
252 mono_domain_unlock (domain);
257 /* The jit_info_table is sorted in ascending order by the end
258 * addresses of the compiled methods. The reason why we have to do
259 * this is that once we introduce tombstones, it becomes possible for
260 * code ranges to overlap, and if we sort by code start and insert at
261 * the back of the table, we cannot guarantee that we won't overlook
264 * There are actually two possible ways to do the sorting and
265 * inserting which work with our lock-free mechanism:
267 * 1. Sort by start address and insert at the front. When looking for
268 * an entry, find the last one with a start address lower than the one
269 * you're looking for, then work your way to the front of the table.
271 * 2. Sort by end address and insert at the back. When looking for an
272 * entry, find the first one with an end address higher than the one
273 * you're looking for, then work your way to the end of the table.
275 * We chose the latter out of convenience.
278 jit_info_table_index (MonoJitInfoTable *table, gint8 *addr)
280 int left = 0, right = table->num_chunks;
282 g_assert (left < right);
285 int pos = (left + right) / 2;
286 MonoJitInfoTableChunk *chunk = table->chunks [pos];
288 if (addr < chunk->last_code_end)
292 } while (left < right);
293 g_assert (left == right);
295 if (left >= table->num_chunks)
296 return table->num_chunks - 1;
301 jit_info_table_chunk_index (MonoJitInfoTableChunk *chunk, MonoThreadHazardPointers *hp, gint8 *addr)
303 int left = 0, right = chunk->num_elements;
305 while (left < right) {
306 int pos = (left + right) / 2;
307 MonoJitInfo *ji = get_hazardous_pointer((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
308 gint8 *code_end = (gint8*)ji->code_start + ji->code_size;
315 g_assert (left == right);
321 jit_info_table_find (MonoJitInfoTable *table, MonoThreadHazardPointers *hp, gint8 *addr)
326 chunk_pos = jit_info_table_index (table, (gint8*)addr);
327 g_assert (chunk_pos < table->num_chunks);
329 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], hp, (gint8*)addr);
331 /* We now have a position that's very close to that of the
332 first element whose end address is higher than the one
333 we're looking for. If we don't have the exact position,
334 then we have a position below that one, so we'll just
335 search upward until we find our element. */
337 MonoJitInfoTableChunk *chunk = table->chunks [chunk_pos];
339 while (pos < chunk->num_elements) {
340 ji = get_hazardous_pointer ((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
344 if (IS_JIT_INFO_TOMBSTONE (ji)) {
345 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
348 if ((gint8*)addr >= (gint8*)ji->code_start
349 && (gint8*)addr < (gint8*)ji->code_start + ji->code_size) {
350 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
354 /* If we find a non-tombstone element which is already
355 beyond what we're looking for, we have to end the
357 if ((gint8*)addr < (gint8*)ji->code_start)
363 } while (chunk_pos < table->num_chunks);
367 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
372 * mono_jit_info_table_find_internal:
374 * If TRY_AOT is FALSE, avoid loading information for missing methods from AOT images, which is currently not async safe.
375 * In this case, only those AOT methods will be found whose jit info is already loaded.
376 * ASYNC SAFETY: When called in an async context (mono_thread_info_is_async_context ()), this is async safe.
377 * In this case, the returned MonoJitInfo might not have metadata information, in particular,
378 * mono_jit_info_get_method () could fail.
381 mono_jit_info_table_find_internal (MonoDomain *domain, char *addr, gboolean try_aot)
383 MonoJitInfoTable *table;
384 MonoJitInfo *ji, *module_ji;
385 MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
387 ++mono_stats.jit_info_table_lookup_count;
389 /* First we have to get the domain's jit_info_table. This is
390 complicated by the fact that a writer might substitute a
391 new table and free the old one. What the writer guarantees
392 us is that it looks at the hazard pointers after it has
393 changed the jit_info_table pointer. So, if we guard the
394 table by a hazard pointer and make sure that the pointer is
395 still there after we've made it hazardous, we don't have to
396 worry about the writer freeing the table. */
397 table = get_hazardous_pointer ((gpointer volatile*)&domain->jit_info_table, hp, JIT_INFO_TABLE_HAZARD_INDEX);
399 ji = jit_info_table_find (table, hp, (gint8*)addr);
401 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
405 /* Maybe its an AOT module */
406 if (try_aot && mono_root_domain && mono_root_domain->aot_modules) {
407 table = get_hazardous_pointer ((gpointer volatile*)&mono_root_domain->aot_modules, hp, JIT_INFO_TABLE_HAZARD_INDEX);
408 module_ji = jit_info_table_find (table, hp, (gint8*)addr);
410 ji = jit_info_find_in_aot_func (domain, module_ji->d.image, addr);
412 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
419 mono_jit_info_table_find (MonoDomain *domain, char *addr)
421 return mono_jit_info_table_find_internal (domain, addr, TRUE);
424 static G_GNUC_UNUSED void
425 jit_info_table_check (MonoJitInfoTable *table)
429 for (i = 0; i < table->num_chunks; ++i) {
430 MonoJitInfoTableChunk *chunk = table->chunks [i];
433 g_assert (chunk->refcount > 0 /* && chunk->refcount <= 8 */);
434 if (chunk->refcount > 10)
435 printf("warning: chunk refcount is %d\n", chunk->refcount);
436 g_assert (chunk->num_elements <= MONO_JIT_INFO_TABLE_CHUNK_SIZE);
438 for (j = 0; j < chunk->num_elements; ++j) {
439 MonoJitInfo *this = chunk->data [j];
442 g_assert ((gint8*)this->code_start + this->code_size <= chunk->last_code_end);
444 if (j < chunk->num_elements - 1)
445 next = chunk->data [j + 1];
446 else if (i < table->num_chunks - 1) {
449 for (k = i + 1; k < table->num_chunks; ++k)
450 if (table->chunks [k]->num_elements > 0)
453 if (k >= table->num_chunks)
456 g_assert (table->chunks [k]->num_elements > 0);
457 next = table->chunks [k]->data [0];
461 g_assert ((gint8*)this->code_start + this->code_size <= (gint8*)next->code_start + next->code_size);
466 static MonoJitInfoTable*
467 jit_info_table_realloc (MonoJitInfoTable *old)
470 int num_elements = jit_info_table_num_elements (old);
473 int new_chunk, new_element;
474 MonoJitInfoTable *new;
476 /* number of needed places for elements needed */
477 required_size = (int)((long)num_elements * JIT_INFO_TABLE_FILL_RATIO_DENOM / JIT_INFO_TABLE_FILL_RATIO_NOM);
478 num_chunks = (required_size + MONO_JIT_INFO_TABLE_CHUNK_SIZE - 1) / MONO_JIT_INFO_TABLE_CHUNK_SIZE;
479 if (num_chunks == 0) {
480 g_assert (num_elements == 0);
481 return jit_info_table_new (old->domain);
483 g_assert (num_chunks > 0);
485 new = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*) * num_chunks);
486 new->domain = old->domain;
487 new->num_chunks = num_chunks;
489 for (i = 0; i < num_chunks; ++i)
490 new->chunks [i] = jit_info_table_new_chunk ();
494 for (i = 0; i < old->num_chunks; ++i) {
495 MonoJitInfoTableChunk *chunk = old->chunks [i];
496 int chunk_num_elements = chunk->num_elements;
499 for (j = 0; j < chunk_num_elements; ++j) {
500 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j])) {
501 g_assert (new_chunk < num_chunks);
502 new->chunks [new_chunk]->data [new_element] = chunk->data [j];
503 if (++new_element >= JIT_INFO_TABLE_FILLED_NUM_ELEMENTS) {
504 new->chunks [new_chunk]->num_elements = new_element;
512 if (new_chunk < num_chunks) {
513 g_assert (new_chunk == num_chunks - 1);
514 new->chunks [new_chunk]->num_elements = new_element;
515 g_assert (new->chunks [new_chunk]->num_elements > 0);
518 for (i = 0; i < num_chunks; ++i) {
519 MonoJitInfoTableChunk *chunk = new->chunks [i];
520 MonoJitInfo *ji = chunk->data [chunk->num_elements - 1];
522 new->chunks [i]->last_code_end = (gint8*)ji->code_start + ji->code_size;
529 jit_info_table_split_chunk (MonoJitInfoTableChunk *chunk, MonoJitInfoTableChunk **new1p, MonoJitInfoTableChunk **new2p)
531 MonoJitInfoTableChunk *new1 = jit_info_table_new_chunk ();
532 MonoJitInfoTableChunk *new2 = jit_info_table_new_chunk ();
534 g_assert (chunk->num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE);
536 new1->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE / 2;
537 new2->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE - new1->num_elements;
539 memcpy ((void*)new1->data, (void*)chunk->data, sizeof (MonoJitInfo*) * new1->num_elements);
540 memcpy ((void*)new2->data, (void*)(chunk->data + new1->num_elements), sizeof (MonoJitInfo*) * new2->num_elements);
542 new1->last_code_end = (gint8*)new1->data [new1->num_elements - 1]->code_start
543 + new1->data [new1->num_elements - 1]->code_size;
544 new2->last_code_end = (gint8*)new2->data [new2->num_elements - 1]->code_start
545 + new2->data [new2->num_elements - 1]->code_size;
551 static MonoJitInfoTable*
552 jit_info_table_copy_and_split_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
554 MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
555 + sizeof (MonoJitInfoTableChunk*) * (table->num_chunks + 1));
558 new_table->domain = table->domain;
559 new_table->num_chunks = table->num_chunks + 1;
562 for (i = 0; i < table->num_chunks; ++i) {
563 if (table->chunks [i] == chunk) {
564 jit_info_table_split_chunk (chunk, &new_table->chunks [j], &new_table->chunks [j + 1]);
567 new_table->chunks [j] = table->chunks [i];
568 ++new_table->chunks [j]->refcount;
573 g_assert (j == new_table->num_chunks);
578 static MonoJitInfoTableChunk*
579 jit_info_table_purify_chunk (MonoJitInfoTableChunk *old)
581 MonoJitInfoTableChunk *new = jit_info_table_new_chunk ();
585 for (i = 0; i < old->num_elements; ++i) {
586 if (!IS_JIT_INFO_TOMBSTONE (old->data [i]))
587 new->data [j++] = old->data [i];
590 new->num_elements = j;
591 if (new->num_elements > 0)
592 new->last_code_end = (gint8*)new->data [j - 1]->code_start + new->data [j - 1]->code_size;
594 new->last_code_end = old->last_code_end;
599 static MonoJitInfoTable*
600 jit_info_table_copy_and_purify_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
602 MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
603 + sizeof (MonoJitInfoTableChunk*) * table->num_chunks);
606 new_table->domain = table->domain;
607 new_table->num_chunks = table->num_chunks;
610 for (i = 0; i < table->num_chunks; ++i) {
611 if (table->chunks [i] == chunk)
612 new_table->chunks [j++] = jit_info_table_purify_chunk (table->chunks [i]);
614 new_table->chunks [j] = table->chunks [i];
615 ++new_table->chunks [j]->refcount;
620 g_assert (j == new_table->num_chunks);
625 /* As we add an element to the table the case can arise that the chunk
626 * to which we need to add is already full. In that case we have to
627 * allocate a new table and do something about that chunk. We have
628 * several strategies:
630 * If the number of elements in the table is below the low watermark
631 * or above the high watermark, we reallocate the whole table.
632 * Otherwise we only concern ourselves with the overflowing chunk:
634 * If there are no tombstones in the chunk then we split the chunk in
635 * two, each half full.
637 * If the chunk does contain tombstones, we just make a new copy of
638 * the chunk without the tombstones, which will have room for at least
639 * the one element we have to add.
641 static MonoJitInfoTable*
642 jit_info_table_chunk_overflow (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
644 int num_elements = jit_info_table_num_elements (table);
647 if (num_elements < JIT_INFO_TABLE_LOW_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)
648 || num_elements > JIT_INFO_TABLE_HIGH_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)) {
649 //printf ("reallocing table\n");
650 return jit_info_table_realloc (table);
653 /* count the number of non-tombstone elements in the chunk */
655 for (i = 0; i < chunk->num_elements; ++i) {
656 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [i]))
660 if (num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
661 //printf ("splitting chunk\n");
662 return jit_info_table_copy_and_split_chunk (table, chunk);
665 //printf ("purifying chunk\n");
666 return jit_info_table_copy_and_purify_chunk (table, chunk);
669 /* We add elements to the table by first making space for them by
670 * shifting the elements at the back to the right, one at a time.
671 * This results in duplicate entries during the process, but during
672 * all the time the table is in a sorted state. Also, when an element
673 * is replaced by another one, the element that replaces it has an end
674 * address that is equal to or lower than that of the replaced
675 * element. That property is necessary to guarantee that when
676 * searching for an element we end up at a position not higher than
677 * the one we're looking for (i.e. we either find the element directly
678 * or we end up to the left of it).
681 jit_info_table_add (MonoDomain *domain, MonoJitInfoTable *volatile *table_ptr, MonoJitInfo *ji)
683 MonoJitInfoTable *table;
684 MonoJitInfoTableChunk *chunk;
692 chunk_pos = jit_info_table_index (table, (gint8*)ji->code_start + ji->code_size);
693 g_assert (chunk_pos < table->num_chunks);
694 chunk = table->chunks [chunk_pos];
696 if (chunk->num_elements >= MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
697 MonoJitInfoTable *new_table = jit_info_table_chunk_overflow (table, chunk);
699 /* Debugging code, should be removed. */
700 //jit_info_table_check (new_table);
702 *table_ptr = new_table;
703 mono_memory_barrier ();
704 domain->num_jit_info_tables++;
705 mono_thread_hazardous_free_or_queue (table, (MonoHazardousFreeFunc)jit_info_table_free, TRUE, FALSE);
711 /* Debugging code, should be removed. */
712 //jit_info_table_check (table);
714 num_elements = chunk->num_elements;
716 pos = jit_info_table_chunk_index (chunk, NULL, (gint8*)ji->code_start + ji->code_size);
718 /* First we need to size up the chunk by one, by copying the
719 last item, or inserting the first one, if the table is
721 if (num_elements > 0)
722 chunk->data [num_elements] = chunk->data [num_elements - 1];
724 chunk->data [0] = ji;
725 mono_memory_write_barrier ();
726 chunk->num_elements = ++num_elements;
728 /* Shift the elements up one by one. */
729 for (i = num_elements - 2; i >= pos; --i) {
730 mono_memory_write_barrier ();
731 chunk->data [i + 1] = chunk->data [i];
734 /* Now we have room and can insert the new item. */
735 mono_memory_write_barrier ();
736 chunk->data [pos] = ji;
738 /* Set the high code end address chunk entry. */
739 chunk->last_code_end = (gint8*)chunk->data [chunk->num_elements - 1]->code_start
740 + chunk->data [chunk->num_elements - 1]->code_size;
742 /* Debugging code, should be removed. */
743 //jit_info_table_check (table);
747 mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
749 g_assert (ji->d.method != NULL);
751 mono_domain_lock (domain);
753 ++mono_stats.jit_info_table_insert_count;
755 jit_info_table_add (domain, &domain->jit_info_table, ji);
757 mono_domain_unlock (domain);
761 mono_jit_info_make_tombstone (MonoJitInfo *ji)
763 MonoJitInfo *tombstone = g_new0 (MonoJitInfo, 1);
765 tombstone->code_start = ji->code_start;
766 tombstone->code_size = ji->code_size;
767 tombstone->d.method = JIT_INFO_TOMBSTONE_MARKER;
773 * LOCKING: domain lock
776 mono_jit_info_free_or_queue (MonoDomain *domain, MonoJitInfo *ji)
778 if (domain->num_jit_info_tables <= 1) {
779 /* Can it actually happen that we only have one table
780 but ji is still hazardous? */
781 mono_thread_hazardous_free_or_queue (ji, g_free, TRUE, FALSE);
783 domain->jit_info_free_queue = g_slist_prepend (domain->jit_info_free_queue, ji);
788 jit_info_table_remove (MonoJitInfoTable *table, MonoJitInfo *ji)
790 MonoJitInfoTableChunk *chunk;
791 gpointer start = ji->code_start;
794 chunk_pos = jit_info_table_index (table, start);
795 g_assert (chunk_pos < table->num_chunks);
797 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], NULL, start);
800 chunk = table->chunks [chunk_pos];
802 while (pos < chunk->num_elements) {
803 if (chunk->data [pos] == ji)
806 g_assert (IS_JIT_INFO_TOMBSTONE (chunk->data [pos]));
807 g_assert ((guint8*)chunk->data [pos]->code_start + chunk->data [pos]->code_size
808 <= (guint8*)ji->code_start + ji->code_size);
815 } while (chunk_pos < table->num_chunks);
818 g_assert (chunk->data [pos] == ji);
820 chunk->data [pos] = mono_jit_info_make_tombstone (ji);
822 /* Debugging code, should be removed. */
823 //jit_info_table_check (table);
827 mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
829 MonoJitInfoTable *table;
831 mono_domain_lock (domain);
832 table = domain->jit_info_table;
834 ++mono_stats.jit_info_table_remove_count;
836 jit_info_table_remove (table, ji);
838 mono_jit_info_free_or_queue (domain, ji);
840 mono_domain_unlock (domain);
844 mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
848 mono_appdomains_lock ();
851 * We reuse MonoJitInfoTable to store AOT module info,
852 * this gives us async-safe lookup.
854 g_assert (mono_root_domain);
855 if (!mono_root_domain->aot_modules) {
856 mono_root_domain->num_jit_info_tables ++;
857 mono_root_domain->aot_modules = jit_info_table_new (mono_root_domain);
860 ji = g_new0 (MonoJitInfo, 1);
862 ji->code_start = start;
863 ji->code_size = (guint8*)end - (guint8*)start;
864 jit_info_table_add (mono_root_domain, &mono_root_domain->aot_modules, ji);
866 mono_appdomains_unlock ();
870 mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func)
872 jit_info_find_in_aot_func = func;
876 mono_jit_info_get_code_start (MonoJitInfo* ji)
878 return ji->code_start;
882 mono_jit_info_get_code_size (MonoJitInfo* ji)
884 return ji->code_size;
888 mono_jit_info_get_method (MonoJitInfo* ji)
890 g_assert (!ji->async);
895 jit_info_key_extract (gpointer value)
897 MonoJitInfo *info = (MonoJitInfo*)value;
899 return info->d.method;
903 jit_info_next_value (gpointer value)
905 MonoJitInfo *info = (MonoJitInfo*)value;
907 return (gpointer*)&info->next_jit_code_hash;
911 mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
913 mono_internal_hash_table_init (jit_code_hash,
914 mono_aligned_addr_hash,
915 jit_info_key_extract,
916 jit_info_next_value);
920 mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
922 if (ji->has_generic_jit_info)
923 return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
929 * mono_jit_info_get_generic_sharing_context:
932 * Returns the jit info's generic sharing context, or NULL if it
935 MonoGenericSharingContext*
936 mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
938 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
941 return gi->generic_sharing_context;
947 * mono_jit_info_set_generic_sharing_context:
949 * @gsctx: a generic sharing context
951 * Sets the jit info's generic sharing context. The jit info must
952 * have memory allocated for the context.
955 mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
957 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
961 gi->generic_sharing_context = gsctx;
964 MonoTryBlockHoleTableJitInfo*
965 mono_jit_info_get_try_block_hole_table_info (MonoJitInfo *ji)
967 if (ji->has_try_block_holes) {
968 char *ptr = (char*)&ji->clauses [ji->num_clauses];
969 if (ji->has_generic_jit_info)
970 ptr += sizeof (MonoGenericJitInfo);
971 return (MonoTryBlockHoleTableJitInfo*)ptr;
978 mono_jit_info_get_arch_eh_info (MonoJitInfo *ji)
980 if (ji->has_arch_eh_info) {
981 char *ptr = (char*)&ji->clauses [ji->num_clauses];
982 if (ji->has_generic_jit_info)
983 ptr += sizeof (MonoGenericJitInfo);
984 if (ji->has_try_block_holes)
985 ptr += sizeof (MonoTryBlockHoleTableJitInfo);
986 return (MonoArchEHJitInfo*)ptr;
993 mono_jit_info_get_cas_info (MonoJitInfo *ji)
995 if (ji->has_cas_info) {
996 char *ptr = (char*)&ji->clauses [ji->num_clauses];
997 if (ji->has_generic_jit_info)
998 ptr += sizeof (MonoGenericJitInfo);
999 if (ji->has_try_block_holes)
1000 ptr += sizeof (MonoTryBlockHoleTableJitInfo);
1001 if (ji->has_arch_eh_info)
1002 ptr += sizeof (MonoArchEHJitInfo);
1003 return (MonoMethodCasInfo*)ptr;
1009 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
1010 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
1012 static LockFreeMempool*
1013 lock_free_mempool_new (void)
1015 return g_new0 (LockFreeMempool, 1);
1019 lock_free_mempool_free (LockFreeMempool *mp)
1021 LockFreeMempoolChunk *chunk, *next;
1026 mono_vfree (chunk, mono_pagesize ());
1032 * This is async safe
1034 static LockFreeMempoolChunk*
1035 lock_free_mempool_chunk_new (LockFreeMempool *mp, int len)
1037 LockFreeMempoolChunk *chunk, *prev;
1040 size = mono_pagesize ();
1041 while (size - sizeof (LockFreeMempoolChunk) < len)
1042 size += mono_pagesize ();
1043 chunk = mono_valloc (0, size, MONO_MMAP_READ|MONO_MMAP_WRITE);
1045 chunk->mem = ALIGN_PTR_TO ((char*)chunk + sizeof (LockFreeMempoolChunk), 16);
1046 chunk->size = ((char*)chunk + size) - (char*)chunk->mem;
1049 /* Add to list of chunks lock-free */
1052 if (InterlockedCompareExchangePointer ((volatile gpointer*)&mp->chunks, chunk, prev) == prev)
1061 * This is async safe
1064 lock_free_mempool_alloc0 (LockFreeMempool *mp, guint size)
1066 LockFreeMempoolChunk *chunk;
1070 // FIXME: Free the allocator
1072 size = ALIGN_TO (size, 8);
1073 chunk = mp->current;
1075 chunk = lock_free_mempool_chunk_new (mp, size);
1076 mono_memory_barrier ();
1078 mp->current = chunk;
1081 /* The code below is lock-free, 'chunk' is shared state */
1082 oldpos = InterlockedExchangeAdd (&chunk->pos, size);
1083 if (oldpos + size > chunk->size) {
1084 chunk = lock_free_mempool_chunk_new (mp, size);
1085 g_assert (chunk->pos + size <= chunk->size);
1088 mono_memory_barrier ();
1089 mp->current = chunk;
1091 res = (char*)chunk->mem + oldpos;
1098 mono_install_create_domain_hook (MonoCreateDomainFunc func)
1100 create_domain_hook = func;
1104 mono_install_free_domain_hook (MonoFreeDomainFunc func)
1106 free_domain_hook = func;
1110 * mono_string_equal:
1111 * @s1: First string to compare
1112 * @s2: Second string to compare
1114 * Returns FALSE if the strings differ.
1117 mono_string_equal (MonoString *s1, MonoString *s2)
1119 int l1 = mono_string_length (s1);
1120 int l2 = mono_string_length (s2);
1127 return memcmp (mono_string_chars (s1), mono_string_chars (s2), l1 * 2) == 0;
1132 * @s: the string to hash
1134 * Returns the hash for the string.
1137 mono_string_hash (MonoString *s)
1139 const guint16 *p = mono_string_chars (s);
1140 int i, len = mono_string_length (s);
1143 for (i = 0; i < len; i++) {
1144 h = (h << 5) - h + *p;
1152 mono_ptrarray_equal (gpointer *s1, gpointer *s2)
1154 int len = GPOINTER_TO_INT (s1 [0]);
1155 if (len != GPOINTER_TO_INT (s2 [0]))
1158 return memcmp (s1 + 1, s2 + 1, len * sizeof(gpointer)) == 0;
1162 mono_ptrarray_hash (gpointer *s)
1165 int len = GPOINTER_TO_INT (s [0]);
1168 for (i = 1; i < len; i++)
1169 hash += GPOINTER_TO_UINT (s [i]);
1175 * Allocate an id for domain and set domain->domain_id.
1176 * LOCKING: must be called while holding appdomains_mutex.
1177 * We try to assign low numbers to the domain, so it can be used
1178 * as an index in data tables to lookup domain-specific info
1179 * with minimal memory overhead. We also try not to reuse the
1180 * same id too quickly (to help debugging).
1183 domain_id_alloc (MonoDomain *domain)
1186 if (!appdomains_list) {
1187 appdomain_list_size = 2;
1188 appdomains_list = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1190 for (i = appdomain_next; i < appdomain_list_size; ++i) {
1191 if (!appdomains_list [i]) {
1197 for (i = 0; i < appdomain_next; ++i) {
1198 if (!appdomains_list [i]) {
1205 MonoDomain **new_list;
1206 int new_size = appdomain_list_size * 2;
1207 if (new_size >= (1 << 16))
1208 g_assert_not_reached ();
1209 id = appdomain_list_size;
1210 new_list = mono_gc_alloc_fixed (new_size * sizeof (void*), NULL);
1211 memcpy (new_list, appdomains_list, appdomain_list_size * sizeof (void*));
1212 mono_gc_free_fixed (appdomains_list);
1213 appdomains_list = new_list;
1214 appdomain_list_size = new_size;
1216 domain->domain_id = id;
1217 appdomains_list [id] = domain;
1219 if (appdomain_next > appdomain_list_size)
1224 static gsize domain_gc_bitmap [sizeof(MonoDomain)/4/32 + 1];
1225 static gpointer domain_gc_desc = NULL;
1226 static guint32 domain_shadow_serial = 0L;
1229 mono_domain_create (void)
1232 guint32 shadow_serial;
1234 mono_appdomains_lock ();
1235 shadow_serial = domain_shadow_serial++;
1237 if (!domain_gc_desc) {
1238 unsigned int i, bit = 0;
1239 for (i = G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_OBJECT); i < G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_GC_TRACKED); i += sizeof (gpointer)) {
1240 bit = i / sizeof (gpointer);
1241 domain_gc_bitmap [bit / 32] |= (gsize) 1 << (bit % 32);
1243 domain_gc_desc = mono_gc_make_descr_from_bitmap ((gsize*)domain_gc_bitmap, bit + 1);
1245 mono_appdomains_unlock ();
1247 #ifdef HAVE_BOEHM_GC
1249 * Boehm doesn't like roots inside GC allocated objects, and alloc_fixed returns
1250 * a GC_MALLOC-ed object, contrary to the api docs. This causes random crashes when
1251 * running the corlib test suite.
1252 * To solve this, we pass a NULL descriptor, and don't register roots.
1254 domain = mono_gc_alloc_fixed (sizeof (MonoDomain), NULL);
1256 domain = mono_gc_alloc_fixed (sizeof (MonoDomain), domain_gc_desc);
1257 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);
1259 domain->shadow_serial = shadow_serial;
1260 domain->domain = NULL;
1261 domain->setup = NULL;
1262 domain->friendly_name = NULL;
1263 domain->search_path = NULL;
1265 mono_profiler_appdomain_event (domain, MONO_PROFILE_START_LOAD);
1267 domain->mp = mono_mempool_new ();
1268 domain->code_mp = mono_code_manager_new ();
1269 domain->lock_free_mp = lock_free_mempool_new ();
1270 domain->env = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1271 domain->domain_assemblies = NULL;
1272 domain->assembly_bindings = NULL;
1273 domain->assembly_bindings_parsed = FALSE;
1274 domain->class_vtable_array = g_ptr_array_new ();
1275 domain->proxy_vtable_hash = g_hash_table_new ((GHashFunc)mono_ptrarray_hash, (GCompareFunc)mono_ptrarray_equal);
1276 domain->static_data_array = NULL;
1277 mono_jit_code_hash_init (&domain->jit_code_hash);
1278 domain->ldstr_table = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1279 domain->num_jit_info_tables = 1;
1280 domain->jit_info_table = jit_info_table_new (domain);
1281 domain->jit_info_free_queue = NULL;
1282 domain->finalizable_objects_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1283 domain->ftnptrs_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1285 InitializeCriticalSection (&domain->lock);
1286 InitializeCriticalSection (&domain->assemblies_lock);
1287 InitializeCriticalSection (&domain->jit_code_hash_lock);
1288 InitializeCriticalSection (&domain->finalizable_objects_hash_lock);
1290 domain->method_rgctx_hash = NULL;
1292 mono_appdomains_lock ();
1293 domain_id_alloc (domain);
1294 mono_appdomains_unlock ();
1296 #ifndef DISABLE_PERFCOUNTERS
1297 mono_perfcounters->loader_appdomains++;
1298 mono_perfcounters->loader_total_appdomains++;
1301 mono_debug_domain_create (domain);
1303 if (create_domain_hook)
1304 create_domain_hook (domain);
1306 mono_profiler_appdomain_loaded (domain, MONO_PROFILE_OK);
1312 * mono_init_internal:
1314 * Creates the initial application domain and initializes the mono_defaults
1316 * This function is guaranteed to not run any IL code.
1317 * If exe_filename is not NULL, the method will determine the required runtime
1318 * from the exe configuration file or the version PE field.
1319 * If runtime_version is not NULL, that runtime version will be used.
1320 * Either exe_filename or runtime_version must be provided.
1322 * Returns: the initial domain.
1325 mono_init_internal (const char *filename, const char *exe_filename, const char *runtime_version)
1327 static MonoDomain *domain = NULL;
1328 MonoAssembly *ass = NULL;
1329 MonoImageOpenStatus status = MONO_IMAGE_OK;
1330 const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
1334 g_assert_not_reached ();
1337 /* Avoid system error message boxes. */
1338 SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1345 #ifndef DISABLE_PERFCOUNTERS
1346 mono_perfcounters_init ();
1349 mono_counters_register ("Max native code in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_size);
1350 mono_counters_register ("Max code space allocated in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_alloc);
1351 mono_counters_register ("Total code space allocated", MONO_COUNTER_INT|MONO_COUNTER_JIT, &total_domain_code_alloc);
1353 mono_gc_base_init ();
1355 MONO_FAST_TLS_INIT (tls_appdomain);
1356 mono_native_tls_alloc (&appdomain_thread_id, NULL);
1358 InitializeCriticalSection (&appdomains_mutex);
1360 mono_metadata_init ();
1361 mono_images_init ();
1362 mono_assemblies_init ();
1363 mono_classes_init ();
1364 mono_loader_init ();
1365 mono_reflection_init ();
1366 mono_runtime_init_tls ();
1368 /* FIXME: When should we release this memory? */
1369 MONO_GC_REGISTER_ROOT_FIXED (appdomains_list);
1371 domain = mono_domain_create ();
1372 mono_root_domain = domain;
1374 SET_APPDOMAIN (domain);
1376 /* Get a list of runtimes supported by the exe */
1377 if (exe_filename != NULL) {
1379 * This function will load the exe file as a MonoImage. We need to close it, but
1380 * that would mean it would be reloaded later. So instead, we save it to
1381 * exe_image, and close it during shutdown.
1383 get_runtimes_from_exe (exe_filename, &exe_image, runtimes);
1386 exe_image = mono_assembly_open_from_bundle (exe_filename, NULL, FALSE);
1388 exe_image = mono_image_open (exe_filename, NULL);
1390 mono_fixup_exe_image (exe_image);
1392 } else if (runtime_version != NULL) {
1393 runtimes [0] = get_runtime_by_version (runtime_version);
1394 runtimes [1] = NULL;
1397 if (runtimes [0] == NULL) {
1398 const MonoRuntimeInfo *default_runtime = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
1399 runtimes [0] = default_runtime;
1400 runtimes [1] = NULL;
1401 g_print ("WARNING: The runtime version supported by this application is unavailable.\n");
1402 g_print ("Using default runtime: %s\n", default_runtime->runtime_version);
1405 /* The selected runtime will be the first one for which there is a mscrolib.dll */
1406 for (n = 0; runtimes [n] != NULL && ass == NULL; n++) {
1407 current_runtime = runtimes [n];
1408 ass = mono_assembly_load_corlib (current_runtime, &status);
1409 if (status != MONO_IMAGE_OK && status != MONO_IMAGE_ERROR_ERRNO)
1414 if ((status != MONO_IMAGE_OK) || (ass == NULL)) {
1416 case MONO_IMAGE_ERROR_ERRNO: {
1417 char *corlib_file = g_build_filename (mono_assembly_getrootdir (), "mono", current_runtime->framework_version, "mscorlib.dll", NULL);
1418 g_print ("The assembly mscorlib.dll was not found or could not be loaded.\n");
1419 g_print ("It should have been installed in the `%s' directory.\n", corlib_file);
1420 g_free (corlib_file);
1423 case MONO_IMAGE_IMAGE_INVALID:
1424 g_print ("The file %s/mscorlib.dll is an invalid CIL image\n",
1425 mono_assembly_getrootdir ());
1427 case MONO_IMAGE_MISSING_ASSEMBLYREF:
1428 g_print ("Missing assembly reference in %s/mscorlib.dll\n",
1429 mono_assembly_getrootdir ());
1432 /* to suppress compiler warning */
1438 mono_defaults.corlib = mono_assembly_get_image (ass);
1440 mono_defaults.object_class = mono_class_from_name (
1441 mono_defaults.corlib, "System", "Object");
1442 g_assert (mono_defaults.object_class != 0);
1444 mono_defaults.void_class = mono_class_from_name (
1445 mono_defaults.corlib, "System", "Void");
1446 g_assert (mono_defaults.void_class != 0);
1448 mono_defaults.boolean_class = mono_class_from_name (
1449 mono_defaults.corlib, "System", "Boolean");
1450 g_assert (mono_defaults.boolean_class != 0);
1452 mono_defaults.byte_class = mono_class_from_name (
1453 mono_defaults.corlib, "System", "Byte");
1454 g_assert (mono_defaults.byte_class != 0);
1456 mono_defaults.sbyte_class = mono_class_from_name (
1457 mono_defaults.corlib, "System", "SByte");
1458 g_assert (mono_defaults.sbyte_class != 0);
1460 mono_defaults.int16_class = mono_class_from_name (
1461 mono_defaults.corlib, "System", "Int16");
1462 g_assert (mono_defaults.int16_class != 0);
1464 mono_defaults.uint16_class = mono_class_from_name (
1465 mono_defaults.corlib, "System", "UInt16");
1466 g_assert (mono_defaults.uint16_class != 0);
1468 mono_defaults.int32_class = mono_class_from_name (
1469 mono_defaults.corlib, "System", "Int32");
1470 g_assert (mono_defaults.int32_class != 0);
1472 mono_defaults.uint32_class = mono_class_from_name (
1473 mono_defaults.corlib, "System", "UInt32");
1474 g_assert (mono_defaults.uint32_class != 0);
1476 mono_defaults.uint_class = mono_class_from_name (
1477 mono_defaults.corlib, "System", "UIntPtr");
1478 g_assert (mono_defaults.uint_class != 0);
1480 mono_defaults.int_class = mono_class_from_name (
1481 mono_defaults.corlib, "System", "IntPtr");
1482 g_assert (mono_defaults.int_class != 0);
1484 mono_defaults.int64_class = mono_class_from_name (
1485 mono_defaults.corlib, "System", "Int64");
1486 g_assert (mono_defaults.int64_class != 0);
1488 mono_defaults.uint64_class = mono_class_from_name (
1489 mono_defaults.corlib, "System", "UInt64");
1490 g_assert (mono_defaults.uint64_class != 0);
1492 mono_defaults.single_class = mono_class_from_name (
1493 mono_defaults.corlib, "System", "Single");
1494 g_assert (mono_defaults.single_class != 0);
1496 mono_defaults.double_class = mono_class_from_name (
1497 mono_defaults.corlib, "System", "Double");
1498 g_assert (mono_defaults.double_class != 0);
1500 mono_defaults.char_class = mono_class_from_name (
1501 mono_defaults.corlib, "System", "Char");
1502 g_assert (mono_defaults.char_class != 0);
1504 mono_defaults.string_class = mono_class_from_name (
1505 mono_defaults.corlib, "System", "String");
1506 g_assert (mono_defaults.string_class != 0);
1508 mono_defaults.enum_class = mono_class_from_name (
1509 mono_defaults.corlib, "System", "Enum");
1510 g_assert (mono_defaults.enum_class != 0);
1512 mono_defaults.array_class = mono_class_from_name (
1513 mono_defaults.corlib, "System", "Array");
1514 g_assert (mono_defaults.array_class != 0);
1516 mono_defaults.delegate_class = mono_class_from_name (
1517 mono_defaults.corlib, "System", "Delegate");
1518 g_assert (mono_defaults.delegate_class != 0 );
1520 mono_defaults.multicastdelegate_class = mono_class_from_name (
1521 mono_defaults.corlib, "System", "MulticastDelegate");
1522 g_assert (mono_defaults.multicastdelegate_class != 0 );
1524 mono_defaults.asyncresult_class = mono_class_from_name (
1525 mono_defaults.corlib, "System.Runtime.Remoting.Messaging",
1527 g_assert (mono_defaults.asyncresult_class != 0 );
1529 mono_defaults.manualresetevent_class = mono_class_from_name (
1530 mono_defaults.corlib, "System.Threading", "ManualResetEvent");
1531 g_assert (mono_defaults.manualresetevent_class != 0 );
1533 mono_defaults.typehandle_class = mono_class_from_name (
1534 mono_defaults.corlib, "System", "RuntimeTypeHandle");
1535 g_assert (mono_defaults.typehandle_class != 0);
1537 mono_defaults.methodhandle_class = mono_class_from_name (
1538 mono_defaults.corlib, "System", "RuntimeMethodHandle");
1539 g_assert (mono_defaults.methodhandle_class != 0);
1541 mono_defaults.fieldhandle_class = mono_class_from_name (
1542 mono_defaults.corlib, "System", "RuntimeFieldHandle");
1543 g_assert (mono_defaults.fieldhandle_class != 0);
1545 mono_defaults.systemtype_class = mono_class_from_name (
1546 mono_defaults.corlib, "System", "Type");
1547 g_assert (mono_defaults.systemtype_class != 0);
1549 mono_defaults.monotype_class = mono_class_from_name (
1550 mono_defaults.corlib, "System", "MonoType");
1551 g_assert (mono_defaults.monotype_class != 0);
1553 mono_defaults.exception_class = mono_class_from_name (
1554 mono_defaults.corlib, "System", "Exception");
1555 g_assert (mono_defaults.exception_class != 0);
1557 mono_defaults.threadabortexception_class = mono_class_from_name (
1558 mono_defaults.corlib, "System.Threading", "ThreadAbortException");
1559 g_assert (mono_defaults.threadabortexception_class != 0);
1561 mono_defaults.thread_class = mono_class_from_name (
1562 mono_defaults.corlib, "System.Threading", "Thread");
1563 g_assert (mono_defaults.thread_class != 0);
1565 mono_defaults.internal_thread_class = mono_class_from_name (
1566 mono_defaults.corlib, "System.Threading", "InternalThread");
1567 if (!mono_defaults.internal_thread_class) {
1568 /* This can happen with an old mscorlib */
1569 fprintf (stderr, "Corlib too old for this runtime.\n");
1570 fprintf (stderr, "Loaded from: %s\n",
1571 mono_defaults.corlib? mono_image_get_filename (mono_defaults.corlib): "unknown");
1575 mono_defaults.appdomain_class = mono_class_from_name (
1576 mono_defaults.corlib, "System", "AppDomain");
1577 g_assert (mono_defaults.appdomain_class != 0);
1579 #ifndef DISABLE_REMOTING
1580 mono_defaults.transparent_proxy_class = mono_class_from_name (
1581 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "TransparentProxy");
1582 g_assert (mono_defaults.transparent_proxy_class != 0);
1584 mono_defaults.real_proxy_class = mono_class_from_name (
1585 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "RealProxy");
1586 g_assert (mono_defaults.real_proxy_class != 0);
1588 mono_defaults.marshalbyrefobject_class = mono_class_from_name (
1589 mono_defaults.corlib, "System", "MarshalByRefObject");
1590 g_assert (mono_defaults.marshalbyrefobject_class != 0);
1592 mono_defaults.iremotingtypeinfo_class = mono_class_from_name (
1593 mono_defaults.corlib, "System.Runtime.Remoting", "IRemotingTypeInfo");
1594 g_assert (mono_defaults.iremotingtypeinfo_class != 0);
1597 mono_defaults.mono_method_message_class = mono_class_from_name (
1598 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", "MonoMethodMessage");
1599 g_assert (mono_defaults.mono_method_message_class != 0);
1601 mono_defaults.field_info_class = mono_class_from_name (
1602 mono_defaults.corlib, "System.Reflection", "FieldInfo");
1603 g_assert (mono_defaults.field_info_class != 0);
1605 mono_defaults.method_info_class = mono_class_from_name (
1606 mono_defaults.corlib, "System.Reflection", "MethodInfo");
1607 g_assert (mono_defaults.method_info_class != 0);
1609 mono_defaults.stringbuilder_class = mono_class_from_name (
1610 mono_defaults.corlib, "System.Text", "StringBuilder");
1611 g_assert (mono_defaults.stringbuilder_class != 0);
1613 mono_defaults.math_class = mono_class_from_name (
1614 mono_defaults.corlib, "System", "Math");
1615 g_assert (mono_defaults.math_class != 0);
1617 mono_defaults.stack_frame_class = mono_class_from_name (
1618 mono_defaults.corlib, "System.Diagnostics", "StackFrame");
1619 g_assert (mono_defaults.stack_frame_class != 0);
1621 mono_defaults.stack_trace_class = mono_class_from_name (
1622 mono_defaults.corlib, "System.Diagnostics", "StackTrace");
1623 g_assert (mono_defaults.stack_trace_class != 0);
1625 mono_defaults.marshal_class = mono_class_from_name (
1626 mono_defaults.corlib, "System.Runtime.InteropServices", "Marshal");
1627 g_assert (mono_defaults.marshal_class != 0);
1629 mono_defaults.typed_reference_class = mono_class_from_name (
1630 mono_defaults.corlib, "System", "TypedReference");
1631 g_assert (mono_defaults.typed_reference_class != 0);
1633 mono_defaults.argumenthandle_class = mono_class_from_name (
1634 mono_defaults.corlib, "System", "RuntimeArgumentHandle");
1635 g_assert (mono_defaults.argumenthandle_class != 0);
1637 mono_defaults.monitor_class = mono_class_from_name (
1638 mono_defaults.corlib, "System.Threading", "Monitor");
1639 g_assert (mono_defaults.monitor_class != 0);
1641 mono_defaults.runtimesecurityframe_class = mono_class_from_name (
1642 mono_defaults.corlib, "System.Security", "RuntimeSecurityFrame");
1644 mono_defaults.executioncontext_class = mono_class_from_name (
1645 mono_defaults.corlib, "System.Threading", "ExecutionContext");
1647 mono_defaults.internals_visible_class = mono_class_from_name (
1648 mono_defaults.corlib, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute");
1650 mono_defaults.critical_finalizer_object = mono_class_from_name (
1651 mono_defaults.corlib, "System.Runtime.ConstrainedExecution", "CriticalFinalizerObject");
1654 * mscorlib needs a little help, only now it can load its friends list (after we have
1655 * loaded the InternalsVisibleToAttribute), load it now
1657 mono_assembly_load_friends (ass);
1659 mono_defaults.safehandle_class = mono_class_from_name (
1660 mono_defaults.corlib, "System.Runtime.InteropServices", "SafeHandle");
1662 mono_defaults.handleref_class = mono_class_from_name (
1663 mono_defaults.corlib, "System.Runtime.InteropServices", "HandleRef");
1665 mono_defaults.attribute_class = mono_class_from_name (
1666 mono_defaults.corlib, "System", "Attribute");
1668 mono_defaults.customattribute_data_class = mono_class_from_name (
1669 mono_defaults.corlib, "System.Reflection", "CustomAttributeData");
1671 /* these are initialized lazily when COM features are used */
1673 mono_class_init (mono_defaults.array_class);
1674 mono_defaults.generic_nullable_class = mono_class_from_name (
1675 mono_defaults.corlib, "System", "Nullable`1");
1676 mono_defaults.generic_ilist_class = mono_class_from_name (
1677 mono_defaults.corlib, "System.Collections.Generic", "IList`1");
1678 mono_defaults.generic_ireadonlylist_class = mono_class_from_name (
1679 mono_defaults.corlib, "System.Collections.Generic", "IReadOnlyList`1");
1681 domain->friendly_name = g_path_get_basename (filename);
1683 _mono_debug_init_corlib (domain);
1691 * Creates the initial application domain and initializes the mono_defaults
1693 * This function is guaranteed to not run any IL code.
1694 * The runtime is initialized using the default runtime version.
1696 * Returns: the initial domain.
1699 mono_init (const char *domain_name)
1701 return mono_init_internal (domain_name, NULL, DEFAULT_RUNTIME_VERSION);
1705 * mono_init_from_assembly:
1706 * @domain_name: name to give to the initial domain
1707 * @filename: filename to load on startup
1709 * Used by the runtime, users should use mono_jit_init instead.
1711 * Creates the initial application domain and initializes the mono_defaults
1713 * This function is guaranteed to not run any IL code.
1714 * The runtime is initialized using the runtime version required by the
1715 * provided executable. The version is determined by looking at the exe
1716 * configuration file and the version PE field)
1718 * Returns: the initial domain.
1721 mono_init_from_assembly (const char *domain_name, const char *filename)
1723 return mono_init_internal (domain_name, filename, NULL);
1727 * mono_init_version:
1729 * Used by the runtime, users should use mono_jit_init instead.
1731 * Creates the initial application domain and initializes the mono_defaults
1734 * This function is guaranteed to not run any IL code.
1735 * The runtime is initialized using the provided rutime version.
1737 * Returns: the initial domain.
1740 mono_init_version (const char *domain_name, const char *version)
1742 return mono_init_internal (domain_name, NULL, version);
1748 * Cleans up all metadata modules.
1753 mono_close_exe_image ();
1755 mono_defaults.corlib = NULL;
1757 mono_config_cleanup ();
1758 mono_loader_cleanup ();
1759 mono_classes_cleanup ();
1760 mono_assemblies_cleanup ();
1761 mono_images_cleanup ();
1762 mono_debug_cleanup ();
1763 mono_metadata_cleanup ();
1765 mono_native_tls_free (appdomain_thread_id);
1766 DeleteCriticalSection (&appdomains_mutex);
1774 mono_close_exe_image (void)
1777 mono_image_close (exe_image);
1781 * mono_get_root_domain:
1783 * The root AppDomain is the initial domain created by the runtime when it is
1784 * initialized. Programs execute on this AppDomain, but can create new ones
1785 * later. Currently there is no unmanaged API to create new AppDomains, this
1786 * must be done from managed code.
1788 * Returns: the root appdomain, to obtain the current domain, use mono_domain_get ()
1791 mono_get_root_domain (void)
1793 return mono_root_domain;
1799 * Returns: the current domain, to obtain the root domain use
1800 * mono_get_root_domain().
1805 return GET_APPDOMAIN ();
1809 mono_domain_unset (void)
1811 SET_APPDOMAIN (NULL);
1815 mono_domain_set_internal_with_options (MonoDomain *domain, gboolean migrate_exception)
1817 MonoInternalThread *thread;
1819 if (mono_domain_get () == domain)
1822 SET_APPDOMAIN (domain);
1823 SET_APPCONTEXT (domain->default_context);
1825 if (migrate_exception) {
1826 thread = mono_thread_internal_current ();
1827 if (!thread->abort_exc)
1830 g_assert (thread->abort_exc->object.vtable->domain != domain);
1831 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
1832 g_assert (thread->abort_exc->object.vtable->domain == domain);
1837 * mono_domain_set_internal:
1838 * @domain: the new domain
1840 * Sets the current domain to @domain.
1843 mono_domain_set_internal (MonoDomain *domain)
1845 mono_domain_set_internal_with_options (domain, TRUE);
1849 mono_domain_foreach (MonoDomainFunc func, gpointer user_data)
1855 * Create a copy of the data to avoid calling the user callback
1856 * inside the lock because that could lead to deadlocks.
1857 * We can do this because this function is not perf. critical.
1859 mono_appdomains_lock ();
1860 size = appdomain_list_size;
1861 copy = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1862 memcpy (copy, appdomains_list, appdomain_list_size * sizeof (void*));
1863 mono_appdomains_unlock ();
1865 for (i = 0; i < size; ++i) {
1867 func (copy [i], user_data);
1870 mono_gc_free_fixed (copy);
1874 * mono_domain_assembly_open:
1875 * @domain: the application domain
1876 * @name: file name of the assembly
1878 * fixme: maybe we should integrate this with mono_assembly_open ??
1881 mono_domain_assembly_open (MonoDomain *domain, const char *name)
1883 MonoDomain *current;
1887 mono_domain_assemblies_lock (domain);
1888 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1890 if (strcmp (name, ass->aname.name) == 0) {
1891 mono_domain_assemblies_unlock (domain);
1895 mono_domain_assemblies_unlock (domain);
1897 if (domain != mono_domain_get ()) {
1898 current = mono_domain_get ();
1900 mono_domain_set (domain, FALSE);
1901 ass = mono_assembly_open (name, NULL);
1902 mono_domain_set (current, FALSE);
1904 ass = mono_assembly_open (name, NULL);
1911 unregister_vtable_reflection_type (MonoVTable *vtable)
1913 MonoObject *type = vtable->type;
1915 if (type->vtable->klass != mono_defaults.monotype_class)
1916 MONO_GC_UNREGISTER_ROOT_IF_MOVING (vtable->type);
1920 mono_domain_free (MonoDomain *domain, gboolean force)
1922 int code_size, code_alloc;
1926 if ((domain == mono_root_domain) && !force) {
1927 g_warning ("cant unload root domain");
1931 if (mono_dont_free_domains)
1934 mono_profiler_appdomain_event (domain, MONO_PROFILE_START_UNLOAD);
1936 mono_debug_domain_unload (domain);
1938 mono_appdomains_lock ();
1939 appdomains_list [domain->domain_id] = NULL;
1940 mono_appdomains_unlock ();
1942 /* must do this early as it accesses fields and types */
1943 if (domain->special_static_fields) {
1944 mono_alloc_special_static_data_free (domain->special_static_fields);
1945 g_hash_table_destroy (domain->special_static_fields);
1946 domain->special_static_fields = NULL;
1950 * We must destroy all these hash tables here because they
1951 * contain references to managed objects belonging to the
1952 * domain. Once we let the GC clear the domain there must be
1953 * no more such references, or we'll crash if a collection
1956 mono_g_hash_table_destroy (domain->ldstr_table);
1957 domain->ldstr_table = NULL;
1959 mono_g_hash_table_destroy (domain->env);
1962 if (domain->tlsrec_list) {
1963 mono_thread_destroy_domain_tls (domain);
1964 domain->tlsrec_list = NULL;
1967 mono_reflection_cleanup_domain (domain);
1969 if (domain->type_hash) {
1970 mono_g_hash_table_destroy (domain->type_hash);
1971 domain->type_hash = NULL;
1973 if (domain->type_init_exception_hash) {
1974 mono_g_hash_table_destroy (domain->type_init_exception_hash);
1975 domain->type_init_exception_hash = NULL;
1978 if (domain->class_vtable_array) {
1980 for (i = 0; i < domain->class_vtable_array->len; ++i)
1981 unregister_vtable_reflection_type (g_ptr_array_index (domain->class_vtable_array, i));
1984 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1985 MonoAssembly *ass = tmp->data;
1986 mono_assembly_release_gc_roots (ass);
1989 /* Have to zero out reference fields since they will be invalidated by the clear_domain () call below */
1990 for (p = (gpointer*)&domain->MONO_DOMAIN_FIRST_OBJECT; p < (gpointer*)&domain->MONO_DOMAIN_FIRST_GC_TRACKED; ++p)
1993 /* This needs to be done before closing assemblies */
1994 mono_gc_clear_domain (domain);
1996 /* Close dynamic assemblies first, since they have no ref count */
1997 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1998 MonoAssembly *ass = tmp->data;
1999 if (!ass->image || !ass->image->dynamic)
2001 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);
2002 if (!mono_assembly_close_except_image_pools (ass))
2006 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2007 MonoAssembly *ass = tmp->data;
2010 if (!ass->image || ass->image->dynamic)
2012 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);
2013 if (!mono_assembly_close_except_image_pools (ass))
2017 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2018 MonoAssembly *ass = tmp->data;
2020 mono_assembly_close_finish (ass);
2022 g_slist_free (domain->domain_assemblies);
2023 domain->domain_assemblies = NULL;
2026 * Send this after the assemblies have been unloaded and the domain is still in a
2029 mono_profiler_appdomain_event (domain, MONO_PROFILE_END_UNLOAD);
2031 if (free_domain_hook)
2032 free_domain_hook (domain);
2034 /* FIXME: free delegate_hash_table when it's used */
2035 if (domain->search_path) {
2036 g_strfreev (domain->search_path);
2037 domain->search_path = NULL;
2039 domain->create_proxy_for_type_method = NULL;
2040 domain->private_invoke_method = NULL;
2041 domain->default_context = NULL;
2042 domain->out_of_memory_ex = NULL;
2043 domain->null_reference_ex = NULL;
2044 domain->stack_overflow_ex = NULL;
2045 domain->ephemeron_tombstone = NULL;
2046 domain->entry_assembly = NULL;
2048 g_free (domain->friendly_name);
2049 domain->friendly_name = NULL;
2050 g_ptr_array_free (domain->class_vtable_array, TRUE);
2051 domain->class_vtable_array = NULL;
2052 g_hash_table_destroy (domain->proxy_vtable_hash);
2053 domain->proxy_vtable_hash = NULL;
2054 if (domain->static_data_array) {
2055 mono_gc_free_fixed (domain->static_data_array);
2056 domain->static_data_array = NULL;
2058 mono_internal_hash_table_destroy (&domain->jit_code_hash);
2061 * There might still be jit info tables of this domain which
2062 * are not freed. Since the domain cannot be in use anymore,
2063 * this will free them.
2065 mono_thread_hazardous_try_free_all ();
2066 if (domain->aot_modules)
2067 jit_info_table_free (domain->aot_modules);
2068 g_assert (domain->num_jit_info_tables == 1);
2069 jit_info_table_free (domain->jit_info_table);
2070 domain->jit_info_table = NULL;
2071 g_assert (!domain->jit_info_free_queue);
2073 /* collect statistics */
2074 code_alloc = mono_code_manager_size (domain->code_mp, &code_size);
2075 total_domain_code_alloc += code_alloc;
2076 max_domain_code_alloc = MAX (max_domain_code_alloc, code_alloc);
2077 max_domain_code_size = MAX (max_domain_code_size, code_size);
2079 #ifdef DEBUG_DOMAIN_UNLOAD
2080 mono_mempool_invalidate (domain->mp);
2081 mono_code_manager_invalidate (domain->code_mp);
2083 #ifndef DISABLE_PERFCOUNTERS
2084 mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (domain->mp);
2086 mono_mempool_destroy (domain->mp);
2088 mono_code_manager_destroy (domain->code_mp);
2089 domain->code_mp = NULL;
2091 lock_free_mempool_free (domain->lock_free_mp);
2092 domain->lock_free_mp = NULL;
2094 g_hash_table_destroy (domain->finalizable_objects_hash);
2095 domain->finalizable_objects_hash = NULL;
2096 if (domain->method_rgctx_hash) {
2097 g_hash_table_destroy (domain->method_rgctx_hash);
2098 domain->method_rgctx_hash = NULL;
2100 if (domain->generic_virtual_cases) {
2101 g_hash_table_destroy (domain->generic_virtual_cases);
2102 domain->generic_virtual_cases = NULL;
2104 if (domain->generic_virtual_thunks) {
2105 g_hash_table_destroy (domain->generic_virtual_thunks);
2106 domain->generic_virtual_thunks = NULL;
2108 if (domain->ftnptrs_hash) {
2109 g_hash_table_destroy (domain->ftnptrs_hash);
2110 domain->ftnptrs_hash = NULL;
2113 DeleteCriticalSection (&domain->finalizable_objects_hash_lock);
2114 DeleteCriticalSection (&domain->assemblies_lock);
2115 DeleteCriticalSection (&domain->jit_code_hash_lock);
2116 DeleteCriticalSection (&domain->lock);
2117 domain->setup = NULL;
2119 mono_gc_deregister_root ((char*)&(domain->MONO_DOMAIN_FIRST_GC_TRACKED));
2121 /* FIXME: anything else required ? */
2123 mono_gc_free_fixed (domain);
2125 #ifndef DISABLE_PERFCOUNTERS
2126 mono_perfcounters->loader_appdomains--;
2129 if (domain == mono_root_domain)
2130 mono_root_domain = NULL;
2134 * mono_domain_get_id:
2137 * Returns: the a domain for a specific domain id.
2140 mono_domain_get_by_id (gint32 domainid)
2142 MonoDomain * domain;
2144 mono_appdomains_lock ();
2145 if (domainid < appdomain_list_size)
2146 domain = appdomains_list [domainid];
2149 mono_appdomains_unlock ();
2155 mono_domain_get_id (MonoDomain *domain)
2157 return domain->domain_id;
2161 * mono_domain_alloc:
2163 * LOCKING: Acquires the domain lock.
2166 mono_domain_alloc (MonoDomain *domain, guint size)
2170 mono_domain_lock (domain);
2171 #ifndef DISABLE_PERFCOUNTERS
2172 mono_perfcounters->loader_bytes += size;
2174 res = mono_mempool_alloc (domain->mp, size);
2175 mono_domain_unlock (domain);
2181 * mono_domain_alloc0:
2183 * LOCKING: Acquires the domain lock.
2186 mono_domain_alloc0 (MonoDomain *domain, guint size)
2190 mono_domain_lock (domain);
2191 #ifndef DISABLE_PERFCOUNTERS
2192 mono_perfcounters->loader_bytes += size;
2194 res = mono_mempool_alloc0 (domain->mp, size);
2195 mono_domain_unlock (domain);
2201 mono_domain_alloc0_lock_free (MonoDomain *domain, guint size)
2203 return lock_free_mempool_alloc0 (domain->lock_free_mp, size);
2207 * mono_domain_code_reserve:
2209 * LOCKING: Acquires the domain lock.
2212 mono_domain_code_reserve (MonoDomain *domain, int size)
2216 mono_domain_lock (domain);
2217 res = mono_code_manager_reserve (domain->code_mp, size);
2218 mono_domain_unlock (domain);
2224 * mono_domain_code_reserve_align:
2226 * LOCKING: Acquires the domain lock.
2229 mono_domain_code_reserve_align (MonoDomain *domain, int size, int alignment)
2233 mono_domain_lock (domain);
2234 res = mono_code_manager_reserve_align (domain->code_mp, size, alignment);
2235 mono_domain_unlock (domain);
2241 * mono_domain_code_commit:
2243 * LOCKING: Acquires the domain lock.
2246 mono_domain_code_commit (MonoDomain *domain, void *data, int size, int newsize)
2248 mono_domain_lock (domain);
2249 mono_code_manager_commit (domain->code_mp, data, size, newsize);
2250 mono_domain_unlock (domain);
2253 #if defined(__native_client_codegen__) && defined(__native_client__)
2255 * Given the temporary buffer (allocated by mono_domain_code_reserve) into which
2256 * we are generating code, return a pointer to the destination in the dynamic
2257 * code segment into which the code will be copied when mono_domain_code_commit
2259 * LOCKING: Acquires the domain lock.
2262 nacl_domain_get_code_dest (MonoDomain *domain, void *data)
2265 mono_domain_lock (domain);
2266 dest = nacl_code_manager_get_code_dest (domain->code_mp, data);
2267 mono_domain_unlock (domain);
2272 * Convenience function which calls mono_domain_code_commit to validate and copy
2273 * the code. The caller sets *buf_base and *buf_size to the start and size of
2274 * the buffer (allocated by mono_domain_code_reserve), and *code_end to the byte
2275 * after the last instruction byte. On return, *buf_base will point to the start
2276 * of the copied in the code segment, and *code_end will point after the end of
2280 nacl_domain_code_validate (MonoDomain *domain, guint8 **buf_base, int buf_size, guint8 **code_end)
2282 guint8 *tmp = nacl_domain_get_code_dest (domain, *buf_base);
2283 mono_domain_code_commit (domain, *buf_base, buf_size, *code_end - *buf_base);
2284 *code_end = tmp + (*code_end - *buf_base);
2290 /* no-op versions of Native Client functions */
2293 nacl_domain_get_code_dest (MonoDomain *domain, void *data)
2299 nacl_domain_code_validate (MonoDomain *domain, guint8 **buf_base, int buf_size, guint8 **code_end)
2306 * mono_domain_code_foreach:
2307 * Iterate over the code thunks of the code manager of @domain.
2309 * The @func callback MUST not take any locks. If it really needs to, it must respect
2310 * the locking rules of the runtime: http://www.mono-project.com/Mono:Runtime:Documentation:ThreadSafety
2311 * LOCKING: Acquires the domain lock.
2315 mono_domain_code_foreach (MonoDomain *domain, MonoCodeManagerFunc func, void *user_data)
2317 mono_domain_lock (domain);
2318 mono_code_manager_foreach (domain->code_mp, func, user_data);
2319 mono_domain_unlock (domain);
2324 mono_context_set (MonoAppContext * new_context)
2326 SET_APPCONTEXT (new_context);
2330 mono_context_get (void)
2332 return GET_APPCONTEXT ();
2335 /* LOCKING: the caller holds the lock for this domain */
2337 mono_domain_add_class_static_data (MonoDomain *domain, MonoClass *klass, gpointer data, guint32 *bitmap)
2339 /* The first entry in the array is the index of the next free slot
2340 * and the total size of the array
2343 if (domain->static_data_array) {
2344 int size = GPOINTER_TO_INT (domain->static_data_array [1]);
2345 next = GPOINTER_TO_INT (domain->static_data_array [0]);
2347 /* 'data' is allocated by alloc_fixed */
2348 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * (size * 2), MONO_GC_ROOT_DESCR_FOR_FIXED (size * 2));
2349 mono_gc_memmove (new_array, domain->static_data_array, sizeof (gpointer) * size);
2351 new_array [1] = GINT_TO_POINTER (size);
2352 mono_gc_free_fixed (domain->static_data_array);
2353 domain->static_data_array = new_array;
2357 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * size, MONO_GC_ROOT_DESCR_FOR_FIXED (size));
2359 new_array [0] = GINT_TO_POINTER (next);
2360 new_array [1] = GINT_TO_POINTER (size);
2361 domain->static_data_array = new_array;
2363 domain->static_data_array [next++] = data;
2364 domain->static_data_array [0] = GINT_TO_POINTER (next);
2368 mono_get_corlib (void)
2370 return mono_defaults.corlib;
2374 mono_get_object_class (void)
2376 return mono_defaults.object_class;
2380 mono_get_byte_class (void)
2382 return mono_defaults.byte_class;
2386 mono_get_void_class (void)
2388 return mono_defaults.void_class;
2392 mono_get_boolean_class (void)
2394 return mono_defaults.boolean_class;
2398 mono_get_sbyte_class (void)
2400 return mono_defaults.sbyte_class;
2404 mono_get_int16_class (void)
2406 return mono_defaults.int16_class;
2410 mono_get_uint16_class (void)
2412 return mono_defaults.uint16_class;
2416 mono_get_int32_class (void)
2418 return mono_defaults.int32_class;
2422 mono_get_uint32_class (void)
2424 return mono_defaults.uint32_class;
2428 mono_get_intptr_class (void)
2430 return mono_defaults.int_class;
2434 mono_get_uintptr_class (void)
2436 return mono_defaults.uint_class;
2440 mono_get_int64_class (void)
2442 return mono_defaults.int64_class;
2446 mono_get_uint64_class (void)
2448 return mono_defaults.uint64_class;
2452 mono_get_single_class (void)
2454 return mono_defaults.single_class;
2458 mono_get_double_class (void)
2460 return mono_defaults.double_class;
2464 mono_get_char_class (void)
2466 return mono_defaults.char_class;
2470 mono_get_string_class (void)
2472 return mono_defaults.string_class;
2476 mono_get_enum_class (void)
2478 return mono_defaults.enum_class;
2482 mono_get_array_class (void)
2484 return mono_defaults.array_class;
2488 mono_get_thread_class (void)
2490 return mono_defaults.thread_class;
2494 mono_get_exception_class (void)
2496 return mono_defaults.exception_class;
2500 static char* get_attribute_value (const gchar **attribute_names,
2501 const gchar **attribute_values,
2502 const char *att_name)
2505 for (n=0; attribute_names[n] != NULL; n++) {
2506 if (strcmp (attribute_names[n], att_name) == 0)
2507 return g_strdup (attribute_values[n]);
2512 static void start_element (GMarkupParseContext *context,
2513 const gchar *element_name,
2514 const gchar **attribute_names,
2515 const gchar **attribute_values,
2519 AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2521 if (strcmp (element_name, "configuration") == 0) {
2522 app_config->configuration_count++;
2525 if (strcmp (element_name, "startup") == 0) {
2526 app_config->startup_count++;
2530 if (app_config->configuration_count != 1 || app_config->startup_count != 1)
2533 if (strcmp (element_name, "requiredRuntime") == 0) {
2534 app_config->required_runtime = get_attribute_value (attribute_names, attribute_values, "version");
2535 } else if (strcmp (element_name, "supportedRuntime") == 0) {
2536 char *version = get_attribute_value (attribute_names, attribute_values, "version");
2537 app_config->supported_runtimes = g_slist_append (app_config->supported_runtimes, version);
2541 static void end_element (GMarkupParseContext *context,
2542 const gchar *element_name,
2546 AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2548 if (strcmp (element_name, "configuration") == 0) {
2549 app_config->configuration_count--;
2550 } else if (strcmp (element_name, "startup") == 0) {
2551 app_config->startup_count--;
2555 static const GMarkupParser
2564 static AppConfigInfo *
2565 app_config_parse (const char *exe_filename)
2567 AppConfigInfo *app_config;
2568 GMarkupParseContext *context;
2571 const char *bundled_config;
2572 char *config_filename;
2574 bundled_config = mono_config_string_for_assembly_file (exe_filename);
2576 if (bundled_config) {
2577 text = g_strdup (bundled_config);
2578 len = strlen (text);
2580 config_filename = g_strconcat (exe_filename, ".config", NULL);
2582 if (!g_file_get_contents (config_filename, &text, &len, NULL)) {
2583 g_free (config_filename);
2586 g_free (config_filename);
2589 app_config = g_new0 (AppConfigInfo, 1);
2591 context = g_markup_parse_context_new (&mono_parser, 0, app_config, NULL);
2592 if (g_markup_parse_context_parse (context, text, len, NULL)) {
2593 g_markup_parse_context_end_parse (context, NULL);
2595 g_markup_parse_context_free (context);
2601 app_config_free (AppConfigInfo* app_config)
2604 GSList *list = app_config->supported_runtimes;
2605 while (list != NULL) {
2606 rt = (char*)list->data;
2608 list = g_slist_next (list);
2610 g_slist_free (app_config->supported_runtimes);
2611 g_free (app_config->required_runtime);
2612 g_free (app_config);
2616 static const MonoRuntimeInfo*
2617 get_runtime_by_version (const char *version)
2620 int max = G_N_ELEMENTS (supported_runtimes);
2626 for (n=0; n<max; n++) {
2627 if (strcmp (version, supported_runtimes[n].runtime_version) == 0)
2628 return &supported_runtimes[n];
2631 vlen = strlen (version);
2632 if (vlen >= 4 && version [1] - '0' >= 4) {
2633 for (n=0; n<max; n++) {
2634 if (strncmp (version, supported_runtimes[n].runtime_version, 4) == 0)
2635 return &supported_runtimes[n];
2643 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes)
2645 AppConfigInfo* app_config;
2647 const MonoRuntimeInfo* runtime = NULL;
2648 MonoImage *image = NULL;
2650 app_config = app_config_parse (exe_file);
2652 if (app_config != NULL) {
2653 /* Check supportedRuntime elements, if none is supported, fail.
2654 * If there are no such elements, look for a requiredRuntime element.
2656 if (app_config->supported_runtimes != NULL) {
2658 GSList *list = app_config->supported_runtimes;
2659 while (list != NULL) {
2660 version = (char*) list->data;
2661 runtime = get_runtime_by_version (version);
2662 if (runtime != NULL)
2663 runtimes [n++] = runtime;
2664 list = g_slist_next (list);
2666 runtimes [n] = NULL;
2667 app_config_free (app_config);
2671 /* Check the requiredRuntime element. This is for 1.0 apps only. */
2672 if (app_config->required_runtime != NULL) {
2673 runtimes [0] = get_runtime_by_version (app_config->required_runtime);
2674 runtimes [1] = NULL;
2675 app_config_free (app_config);
2678 app_config_free (app_config);
2681 /* Look for a runtime with the exact version */
2682 image = mono_assembly_open_from_bundle (exe_file, NULL, FALSE);
2685 image = mono_image_open (exe_file, NULL);
2687 if (image == NULL) {
2688 /* The image is wrong or the file was not found. In this case return
2689 * a default runtime and leave to the initialization method the work of
2690 * reporting the error.
2692 runtimes [0] = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
2693 runtimes [1] = NULL;
2699 runtimes [0] = get_runtime_by_version (image->version);
2700 runtimes [1] = NULL;
2705 * mono_get_runtime_info:
2707 * Returns: the version of the current runtime instance.
2709 const MonoRuntimeInfo*
2710 mono_get_runtime_info (void)
2712 return current_runtime;
2716 mono_debugger_check_runtime_version (const char *filename)
2718 const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
2719 const MonoRuntimeInfo *rinfo;
2722 get_runtimes_from_exe (filename, &image, runtimes);
2723 rinfo = runtimes [0];
2726 return g_strdup_printf ("Cannot get runtime version from assembly `%s'", filename);
2728 if (rinfo != current_runtime)
2729 return g_strdup_printf ("The Mono Debugger is currently using the `%s' runtime, but "
2730 "the assembly `%s' requires version `%s'", current_runtime->runtime_version,
2731 filename, rinfo->runtime_version);
2737 * mono_framework_version:
2739 * Return the major version of the framework curently executing.
2742 mono_framework_version (void)
2744 return current_runtime->framework_version [0] - '0';