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)
17 #include <mono/metadata/gc-internal.h>
19 #include <mono/utils/mono-compiler.h>
20 #include <mono/utils/mono-logger-internal.h>
21 #include <mono/utils/mono-membar.h>
22 #include <mono/utils/mono-counters.h>
23 #include <mono/metadata/object.h>
24 #include <mono/metadata/object-internals.h>
25 #include <mono/metadata/domain-internals.h>
26 #include <mono/metadata/class-internals.h>
27 #include <mono/metadata/assembly.h>
28 #include <mono/metadata/exception.h>
29 #include <mono/metadata/metadata-internals.h>
30 #include <mono/metadata/gc-internal.h>
31 #include <mono/metadata/appdomain.h>
32 #include <mono/metadata/mono-debug-debugger.h>
33 #include <mono/metadata/mono-config.h>
34 #include <mono/metadata/threads-types.h>
35 #include <metadata/threads.h>
36 #include <metadata/profiler-private.h>
37 #include <mono/metadata/coree.h>
39 /* #define DEBUG_DOMAIN_UNLOAD */
41 /* we need to use both the Tls* functions and __thread because
42 * some archs may generate faster jit code with one meachanism
43 * or the other (we used to do it because tls slots were GC-tracked,
44 * but we can't depend on this).
46 static guint32 appdomain_thread_id = -1;
49 * Avoid calling TlsSetValue () if possible, since in the io-layer, it acquires
50 * a global lock (!) so it is a contention point.
52 #if (defined(__i386__) || defined(__x86_64__)) && !defined(HOST_WIN32)
53 #define NO_TLS_SET_VALUE
58 static __thread MonoDomain * tls_appdomain MONO_TLS_FAST;
60 #define GET_APPDOMAIN() tls_appdomain
62 #ifdef NO_TLS_SET_VALUE
63 #define SET_APPDOMAIN(x) do { \
67 #define SET_APPDOMAIN(x) do { \
69 TlsSetValue (appdomain_thread_id, x); \
73 #else /* !HAVE_KW_THREAD */
75 #define GET_APPDOMAIN() ((MonoDomain *)TlsGetValue (appdomain_thread_id))
76 #define SET_APPDOMAIN(x) TlsSetValue (appdomain_thread_id, x);
80 #define GET_APPCONTEXT() (mono_thread_internal_current ()->current_appcontext)
81 #define SET_APPCONTEXT(x) MONO_OBJECT_SETREF (mono_thread_internal_current (), current_appcontext, (x))
83 static guint16 appdomain_list_size = 0;
84 static guint16 appdomain_next = 0;
85 static MonoDomain **appdomains_list = NULL;
86 static MonoImage *exe_image;
88 gboolean mono_dont_free_domains;
90 #define mono_appdomains_lock() EnterCriticalSection (&appdomains_mutex)
91 #define mono_appdomains_unlock() LeaveCriticalSection (&appdomains_mutex)
92 static CRITICAL_SECTION appdomains_mutex;
94 static MonoDomain *mono_root_domain = NULL;
97 static int max_domain_code_size = 0;
98 static int max_domain_code_alloc = 0;
99 static int total_domain_code_alloc = 0;
101 /* AppConfigInfo: Information about runtime versions supported by an
105 GSList *supported_runtimes;
106 char *required_runtime;
107 int configuration_count;
112 * AotModuleInfo: Contains information about AOT modules.
119 static const MonoRuntimeInfo *current_runtime = NULL;
121 static MonoJitInfoFindInAot jit_info_find_in_aot_func = NULL;
124 * Contains information about AOT loaded code.
126 static MonoAotModuleInfoTable *aot_modules = NULL;
128 /* This is the list of runtime versions supported by this JIT.
130 static const MonoRuntimeInfo supported_runtimes[] = {
131 {"v2.0.50215","2.0", { {2,0,0,0}, {8,0,0,0} } },
132 {"v2.0.50727","2.0", { {2,0,0,0}, {8,0,0,0} } },
133 {"v4.0.21006","4.0", { {4,0,0,0}, {10,0,0,0} } },
134 {"v4.0.30128","4.0", { {4,0,0,0}, {10,0,0,0} } },
135 {"moonlight", "2.1", { {2,0,5,0}, {9,0,0,0} } },
139 /* The stable runtime version */
140 #define DEFAULT_RUNTIME_VERSION "v2.0.50727"
142 /* Callbacks installed by the JIT */
143 static MonoCreateDomainFunc create_domain_hook;
144 static MonoFreeDomainFunc free_domain_hook;
146 /* This is intentionally not in the header file, so people don't misuse it. */
147 extern void _mono_debug_init_corlib (MonoDomain *domain);
150 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes);
152 static const MonoRuntimeInfo*
153 get_runtime_by_version (const char *version);
156 mono_jit_info_find_aot_module (guint8* addr);
159 mono_domain_get_tls_key (void)
161 #ifdef NO_TLS_SET_VALUE
162 g_assert_not_reached ();
165 return appdomain_thread_id;
170 mono_domain_get_tls_offset (void)
173 MONO_THREAD_VAR_OFFSET (tls_appdomain, offset);
174 /* __asm ("jmp 1f; .section writetext, \"awx\"; 1: movl $tls_appdomain@ntpoff, %0; jmp 2f; .previous; 2:"
179 #define JIT_INFO_TABLE_FILL_RATIO_NOM 3
180 #define JIT_INFO_TABLE_FILL_RATIO_DENOM 4
181 #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)
183 #define JIT_INFO_TABLE_LOW_WATERMARK(n) ((n) / 2)
184 #define JIT_INFO_TABLE_HIGH_WATERMARK(n) ((n) * 5 / 6)
186 #define JIT_INFO_TOMBSTONE_MARKER ((MonoMethod*)NULL)
187 #define IS_JIT_INFO_TOMBSTONE(ji) ((ji)->method == JIT_INFO_TOMBSTONE_MARKER)
189 #define JIT_INFO_TABLE_HAZARD_INDEX 0
190 #define JIT_INFO_HAZARD_INDEX 1
193 jit_info_table_num_elements (MonoJitInfoTable *table)
196 int num_elements = 0;
198 for (i = 0; i < table->num_chunks; ++i) {
199 MonoJitInfoTableChunk *chunk = table->chunks [i];
200 int chunk_num_elements = chunk->num_elements;
203 for (j = 0; j < chunk_num_elements; ++j) {
204 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j]))
212 static MonoJitInfoTableChunk*
213 jit_info_table_new_chunk (void)
215 MonoJitInfoTableChunk *chunk = g_new0 (MonoJitInfoTableChunk, 1);
221 static MonoJitInfoTable *
222 jit_info_table_new (MonoDomain *domain)
224 MonoJitInfoTable *table = g_malloc0 (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*));
226 table->domain = domain;
227 table->num_chunks = 1;
228 table->chunks [0] = jit_info_table_new_chunk ();
234 jit_info_table_free (MonoJitInfoTable *table)
237 int num_chunks = table->num_chunks;
238 MonoDomain *domain = table->domain;
240 mono_domain_lock (domain);
242 table->domain->num_jit_info_tables--;
243 if (table->domain->num_jit_info_tables <= 1) {
246 for (list = table->domain->jit_info_free_queue; list; list = list->next)
249 g_slist_free (table->domain->jit_info_free_queue);
250 table->domain->jit_info_free_queue = NULL;
253 /* At this point we assume that there are no other threads
254 still accessing the table, so we don't have to worry about
255 hazardous pointers. */
257 for (i = 0; i < num_chunks; ++i) {
258 MonoJitInfoTableChunk *chunk = table->chunks [i];
262 if (--chunk->refcount > 0)
265 num_elements = chunk->num_elements;
266 for (j = 0; j < num_elements; ++j) {
267 MonoJitInfo *ji = chunk->data [j];
269 if (IS_JIT_INFO_TOMBSTONE (ji))
276 mono_domain_unlock (domain);
281 /* Can be called with hp==NULL, in which case it acts as an ordinary
282 pointer fetch. It's used that way indirectly from
283 mono_jit_info_table_add(), which doesn't have to care about hazards
284 because it holds the respective domain lock. */
286 get_hazardous_pointer (gpointer volatile *pp, MonoThreadHazardPointers *hp, int hazard_index)
291 /* Get the pointer */
293 /* If we don't have hazard pointers just return the
297 /* Make it hazardous */
298 mono_hazard_pointer_set (hp, hazard_index, p);
299 /* Check that it's still the same. If not, try
302 mono_hazard_pointer_clear (hp, hazard_index);
311 /* The jit_info_table is sorted in ascending order by the end
312 * addresses of the compiled methods. The reason why we have to do
313 * this is that once we introduce tombstones, it becomes possible for
314 * code ranges to overlap, and if we sort by code start and insert at
315 * the back of the table, we cannot guarantee that we won't overlook
318 * There are actually two possible ways to do the sorting and
319 * inserting which work with our lock-free mechanism:
321 * 1. Sort by start address and insert at the front. When looking for
322 * an entry, find the last one with a start address lower than the one
323 * you're looking for, then work your way to the front of the table.
325 * 2. Sort by end address and insert at the back. When looking for an
326 * entry, find the first one with an end address higher than the one
327 * you're looking for, then work your way to the end of the table.
329 * We chose the latter out of convenience.
332 jit_info_table_index (MonoJitInfoTable *table, gint8 *addr)
334 int left = 0, right = table->num_chunks;
336 g_assert (left < right);
339 int pos = (left + right) / 2;
340 MonoJitInfoTableChunk *chunk = table->chunks [pos];
342 if (addr < chunk->last_code_end)
346 } while (left < right);
347 g_assert (left == right);
349 if (left >= table->num_chunks)
350 return table->num_chunks - 1;
355 jit_info_table_chunk_index (MonoJitInfoTableChunk *chunk, MonoThreadHazardPointers *hp, gint8 *addr)
357 int left = 0, right = chunk->num_elements;
359 while (left < right) {
360 int pos = (left + right) / 2;
361 MonoJitInfo *ji = get_hazardous_pointer((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
362 gint8 *code_end = (gint8*)ji->code_start + ji->code_size;
369 g_assert (left == right);
375 mono_jit_info_table_find (MonoDomain *domain, char *addr)
377 MonoJitInfoTable *table;
380 MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
383 ++mono_stats.jit_info_table_lookup_count;
385 /* First we have to get the domain's jit_info_table. This is
386 complicated by the fact that a writer might substitute a
387 new table and free the old one. What the writer guarantees
388 us is that it looks at the hazard pointers after it has
389 changed the jit_info_table pointer. So, if we guard the
390 table by a hazard pointer and make sure that the pointer is
391 still there after we've made it hazardous, we don't have to
392 worry about the writer freeing the table. */
393 table = get_hazardous_pointer ((gpointer volatile*)&domain->jit_info_table, hp, JIT_INFO_TABLE_HAZARD_INDEX);
395 chunk_pos = jit_info_table_index (table, (gint8*)addr);
396 g_assert (chunk_pos < table->num_chunks);
398 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], hp, (gint8*)addr);
400 /* We now have a position that's very close to that of the
401 first element whose end address is higher than the one
402 we're looking for. If we don't have the exact position,
403 then we have a position below that one, so we'll just
404 search upward until we find our element. */
406 MonoJitInfoTableChunk *chunk = table->chunks [chunk_pos];
408 while (pos < chunk->num_elements) {
409 ji = get_hazardous_pointer ((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
413 if (IS_JIT_INFO_TOMBSTONE (ji)) {
414 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
417 if ((gint8*)addr >= (gint8*)ji->code_start
418 && (gint8*)addr < (gint8*)ji->code_start + ji->code_size) {
419 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
420 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
424 /* If we find a non-tombstone element which is already
425 beyond what we're looking for, we have to end the
427 if ((gint8*)addr < (gint8*)ji->code_start)
433 } while (chunk_pos < table->num_chunks);
436 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
437 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
441 /* Maybe its an AOT module */
442 image = mono_jit_info_find_aot_module ((guint8*)addr);
444 ji = jit_info_find_in_aot_func (domain, image, addr);
449 static G_GNUC_UNUSED void
450 jit_info_table_check (MonoJitInfoTable *table)
454 for (i = 0; i < table->num_chunks; ++i) {
455 MonoJitInfoTableChunk *chunk = table->chunks [i];
458 g_assert (chunk->refcount > 0 /* && chunk->refcount <= 8 */);
459 if (chunk->refcount > 10)
460 printf("warning: chunk refcount is %d\n", chunk->refcount);
461 g_assert (chunk->num_elements <= MONO_JIT_INFO_TABLE_CHUNK_SIZE);
463 for (j = 0; j < chunk->num_elements; ++j) {
464 MonoJitInfo *this = chunk->data [j];
467 g_assert ((gint8*)this->code_start + this->code_size <= chunk->last_code_end);
469 if (j < chunk->num_elements - 1)
470 next = chunk->data [j + 1];
471 else if (i < table->num_chunks - 1) {
474 for (k = i + 1; k < table->num_chunks; ++k)
475 if (table->chunks [k]->num_elements > 0)
478 if (k >= table->num_chunks)
481 g_assert (table->chunks [k]->num_elements > 0);
482 next = table->chunks [k]->data [0];
486 g_assert ((gint8*)this->code_start + this->code_size <= (gint8*)next->code_start + next->code_size);
491 static MonoJitInfoTable*
492 jit_info_table_realloc (MonoJitInfoTable *old)
495 int num_elements = jit_info_table_num_elements (old);
498 int new_chunk, new_element;
499 MonoJitInfoTable *new;
501 /* number of needed places for elements needed */
502 required_size = (int)((long)num_elements * JIT_INFO_TABLE_FILL_RATIO_DENOM / JIT_INFO_TABLE_FILL_RATIO_NOM);
503 num_chunks = (required_size + MONO_JIT_INFO_TABLE_CHUNK_SIZE - 1) / MONO_JIT_INFO_TABLE_CHUNK_SIZE;
505 new = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*) * num_chunks);
506 new->domain = old->domain;
507 new->num_chunks = num_chunks;
509 for (i = 0; i < num_chunks; ++i)
510 new->chunks [i] = jit_info_table_new_chunk ();
514 for (i = 0; i < old->num_chunks; ++i) {
515 MonoJitInfoTableChunk *chunk = old->chunks [i];
516 int chunk_num_elements = chunk->num_elements;
519 for (j = 0; j < chunk_num_elements; ++j) {
520 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j])) {
521 g_assert (new_chunk < num_chunks);
522 new->chunks [new_chunk]->data [new_element] = chunk->data [j];
523 if (++new_element >= JIT_INFO_TABLE_FILLED_NUM_ELEMENTS) {
524 new->chunks [new_chunk]->num_elements = new_element;
532 if (new_chunk < num_chunks) {
533 g_assert (new_chunk == num_chunks - 1);
534 new->chunks [new_chunk]->num_elements = new_element;
535 g_assert (new->chunks [new_chunk]->num_elements > 0);
538 for (i = 0; i < num_chunks; ++i) {
539 MonoJitInfoTableChunk *chunk = new->chunks [i];
540 MonoJitInfo *ji = chunk->data [chunk->num_elements - 1];
542 new->chunks [i]->last_code_end = (gint8*)ji->code_start + ji->code_size;
549 jit_info_table_split_chunk (MonoJitInfoTableChunk *chunk, MonoJitInfoTableChunk **new1p, MonoJitInfoTableChunk **new2p)
551 MonoJitInfoTableChunk *new1 = jit_info_table_new_chunk ();
552 MonoJitInfoTableChunk *new2 = jit_info_table_new_chunk ();
554 g_assert (chunk->num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE);
556 new1->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE / 2;
557 new2->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE - new1->num_elements;
559 memcpy ((void*)new1->data, (void*)chunk->data, sizeof (MonoJitInfo*) * new1->num_elements);
560 memcpy ((void*)new2->data, (void*)(chunk->data + new1->num_elements), sizeof (MonoJitInfo*) * new2->num_elements);
562 new1->last_code_end = (gint8*)new1->data [new1->num_elements - 1]->code_start
563 + new1->data [new1->num_elements - 1]->code_size;
564 new2->last_code_end = (gint8*)new2->data [new2->num_elements - 1]->code_start
565 + new2->data [new2->num_elements - 1]->code_size;
571 static MonoJitInfoTable*
572 jit_info_table_copy_and_split_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
574 MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
575 + sizeof (MonoJitInfoTableChunk*) * (table->num_chunks + 1));
578 new_table->domain = table->domain;
579 new_table->num_chunks = table->num_chunks + 1;
582 for (i = 0; i < table->num_chunks; ++i) {
583 if (table->chunks [i] == chunk) {
584 jit_info_table_split_chunk (chunk, &new_table->chunks [j], &new_table->chunks [j + 1]);
587 new_table->chunks [j] = table->chunks [i];
588 ++new_table->chunks [j]->refcount;
593 g_assert (j == new_table->num_chunks);
598 static MonoJitInfoTableChunk*
599 jit_info_table_purify_chunk (MonoJitInfoTableChunk *old)
601 MonoJitInfoTableChunk *new = jit_info_table_new_chunk ();
605 for (i = 0; i < old->num_elements; ++i) {
606 if (!IS_JIT_INFO_TOMBSTONE (old->data [i]))
607 new->data [j++] = old->data [i];
610 new->num_elements = j;
611 if (new->num_elements > 0)
612 new->last_code_end = (gint8*)new->data [j - 1]->code_start + new->data [j - 1]->code_size;
614 new->last_code_end = old->last_code_end;
619 static MonoJitInfoTable*
620 jit_info_table_copy_and_purify_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
622 MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
623 + sizeof (MonoJitInfoTableChunk*) * table->num_chunks);
626 new_table->domain = table->domain;
627 new_table->num_chunks = table->num_chunks;
630 for (i = 0; i < table->num_chunks; ++i) {
631 if (table->chunks [i] == chunk)
632 new_table->chunks [j++] = jit_info_table_purify_chunk (table->chunks [i]);
634 new_table->chunks [j] = table->chunks [i];
635 ++new_table->chunks [j]->refcount;
640 g_assert (j == new_table->num_chunks);
645 /* As we add an element to the table the case can arise that the chunk
646 * to which we need to add is already full. In that case we have to
647 * allocate a new table and do something about that chunk. We have
648 * several strategies:
650 * If the number of elements in the table is below the low watermark
651 * or above the high watermark, we reallocate the whole table.
652 * Otherwise we only concern ourselves with the overflowing chunk:
654 * If there are no tombstones in the chunk then we split the chunk in
655 * two, each half full.
657 * If the chunk does contain tombstones, we just make a new copy of
658 * the chunk without the tombstones, which will have room for at least
659 * the one element we have to add.
661 static MonoJitInfoTable*
662 jit_info_table_chunk_overflow (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
664 int num_elements = jit_info_table_num_elements (table);
667 if (num_elements < JIT_INFO_TABLE_LOW_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)
668 || num_elements > JIT_INFO_TABLE_HIGH_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)) {
669 //printf ("reallocing table\n");
670 return jit_info_table_realloc (table);
673 /* count the number of non-tombstone elements in the chunk */
675 for (i = 0; i < chunk->num_elements; ++i) {
676 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [i]))
680 if (num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
681 //printf ("splitting chunk\n");
682 return jit_info_table_copy_and_split_chunk (table, chunk);
685 //printf ("purifying chunk\n");
686 return jit_info_table_copy_and_purify_chunk (table, chunk);
689 /* We add elements to the table by first making space for them by
690 * shifting the elements at the back to the right, one at a time.
691 * This results in duplicate entries during the process, but during
692 * all the time the table is in a sorted state. Also, when an element
693 * is replaced by another one, the element that replaces it has an end
694 * address that is equal to or lower than that of the replaced
695 * element. That property is necessary to guarantee that when
696 * searching for an element we end up at a position not higher than
697 * the one we're looking for (i.e. we either find the element directly
698 * or we end up to the left of it).
701 mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
703 MonoJitInfoTable *table;
705 MonoJitInfoTableChunk *chunk;
709 g_assert (ji->method != NULL);
711 mono_domain_lock (domain);
713 ++mono_stats.jit_info_table_insert_count;
715 table = domain->jit_info_table;
718 chunk_pos = jit_info_table_index (table, (gint8*)ji->code_start + ji->code_size);
719 g_assert (chunk_pos < table->num_chunks);
720 chunk = table->chunks [chunk_pos];
722 if (chunk->num_elements >= MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
723 MonoJitInfoTable *new_table = jit_info_table_chunk_overflow (table, chunk);
725 /* Debugging code, should be removed. */
726 //jit_info_table_check (new_table);
728 domain->jit_info_table = new_table;
729 mono_memory_barrier ();
730 domain->num_jit_info_tables++;
731 mono_thread_hazardous_free_or_queue (table, (MonoHazardousFreeFunc)jit_info_table_free);
737 /* Debugging code, should be removed. */
738 //jit_info_table_check (table);
740 num_elements = chunk->num_elements;
742 pos = jit_info_table_chunk_index (chunk, NULL, (gint8*)ji->code_start + ji->code_size);
744 /* First we need to size up the chunk by one, by copying the
745 last item, or inserting the first one, if the table is
747 if (num_elements > 0)
748 chunk->data [num_elements] = chunk->data [num_elements - 1];
750 chunk->data [0] = ji;
751 mono_memory_write_barrier ();
752 chunk->num_elements = ++num_elements;
754 /* Shift the elements up one by one. */
755 for (i = num_elements - 2; i >= pos; --i) {
756 mono_memory_write_barrier ();
757 chunk->data [i + 1] = chunk->data [i];
760 /* Now we have room and can insert the new item. */
761 mono_memory_write_barrier ();
762 chunk->data [pos] = ji;
764 /* Set the high code end address chunk entry. */
765 chunk->last_code_end = (gint8*)chunk->data [chunk->num_elements - 1]->code_start
766 + chunk->data [chunk->num_elements - 1]->code_size;
768 /* Debugging code, should be removed. */
769 //jit_info_table_check (table);
771 mono_domain_unlock (domain);
775 mono_jit_info_make_tombstone (MonoJitInfo *ji)
777 MonoJitInfo *tombstone = g_new0 (MonoJitInfo, 1);
779 tombstone->code_start = ji->code_start;
780 tombstone->code_size = ji->code_size;
781 tombstone->method = JIT_INFO_TOMBSTONE_MARKER;
787 * LOCKING: domain lock
790 mono_jit_info_free_or_queue (MonoDomain *domain, MonoJitInfo *ji)
792 if (domain->num_jit_info_tables <= 1) {
793 /* Can it actually happen that we only have one table
794 but ji is still hazardous? */
795 mono_thread_hazardous_free_or_queue (ji, g_free);
797 domain->jit_info_free_queue = g_slist_prepend (domain->jit_info_free_queue, ji);
802 mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
804 MonoJitInfoTable *table;
805 MonoJitInfoTableChunk *chunk;
806 gpointer start = ji->code_start;
809 mono_domain_lock (domain);
810 table = domain->jit_info_table;
812 ++mono_stats.jit_info_table_remove_count;
814 chunk_pos = jit_info_table_index (table, start);
815 g_assert (chunk_pos < table->num_chunks);
817 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], NULL, start);
820 chunk = table->chunks [chunk_pos];
822 while (pos < chunk->num_elements) {
823 if (chunk->data [pos] == ji)
826 g_assert (IS_JIT_INFO_TOMBSTONE (chunk->data [pos]));
827 g_assert ((guint8*)chunk->data [pos]->code_start + chunk->data [pos]->code_size
828 <= (guint8*)ji->code_start + ji->code_size);
835 } while (chunk_pos < table->num_chunks);
838 g_assert (chunk->data [pos] == ji);
840 chunk->data [pos] = mono_jit_info_make_tombstone (ji);
842 /* Debugging code, should be removed. */
843 //jit_info_table_check (table);
845 mono_jit_info_free_or_queue (domain, ji);
847 mono_domain_unlock (domain);
850 static MonoAotModuleInfoTable*
851 mono_aot_module_info_table_new (void)
853 return g_array_new (FALSE, FALSE, sizeof (gpointer));
857 aot_info_table_index (MonoAotModuleInfoTable *table, char *addr)
859 int left = 0, right = table->len;
861 while (left < right) {
862 int pos = (left + right) / 2;
863 AotModuleInfo *ainfo = g_array_index (table, gpointer, pos);
864 char *start = ainfo->start;
865 char *end = ainfo->end;
869 else if (addr >= end)
879 mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
881 AotModuleInfo *ainfo = g_new0 (AotModuleInfo, 1);
884 ainfo->image = image;
885 ainfo->start = start;
888 mono_appdomains_lock ();
891 aot_modules = mono_aot_module_info_table_new ();
893 pos = aot_info_table_index (aot_modules, start);
895 g_array_insert_val (aot_modules, pos, ainfo);
897 mono_appdomains_unlock ();
901 mono_jit_info_find_aot_module (guint8* addr)
903 guint left = 0, right;
908 mono_appdomains_lock ();
910 right = aot_modules->len;
911 while (left < right) {
912 guint pos = (left + right) / 2;
913 AotModuleInfo *ai = g_array_index (aot_modules, gpointer, pos);
915 if (addr < (guint8*)ai->start)
917 else if (addr >= (guint8*)ai->end)
920 mono_appdomains_unlock ();
925 mono_appdomains_unlock ();
931 mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func)
933 jit_info_find_in_aot_func = func;
937 mono_jit_info_get_code_start (MonoJitInfo* ji)
939 return ji->code_start;
943 mono_jit_info_get_code_size (MonoJitInfo* ji)
945 return ji->code_size;
949 mono_jit_info_get_method (MonoJitInfo* ji)
955 jit_info_key_extract (gpointer value)
957 MonoJitInfo *info = (MonoJitInfo*)value;
963 jit_info_next_value (gpointer value)
965 MonoJitInfo *info = (MonoJitInfo*)value;
967 return (gpointer*)&info->next_jit_code_hash;
971 mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
973 mono_internal_hash_table_init (jit_code_hash,
974 mono_aligned_addr_hash,
975 jit_info_key_extract,
976 jit_info_next_value);
980 mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
982 if (ji->has_generic_jit_info)
983 return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
989 * mono_jit_info_get_generic_sharing_context:
992 * Returns the jit info's generic sharing context, or NULL if it
995 MonoGenericSharingContext*
996 mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
998 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
1001 return gi->generic_sharing_context;
1007 * mono_jit_info_set_generic_sharing_context:
1009 * @gsctx: a generic sharing context
1011 * Sets the jit info's generic sharing context. The jit info must
1012 * have memory allocated for the context.
1015 mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
1017 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
1021 gi->generic_sharing_context = gsctx;
1025 mono_install_create_domain_hook (MonoCreateDomainFunc func)
1027 create_domain_hook = func;
1031 mono_install_free_domain_hook (MonoFreeDomainFunc func)
1033 free_domain_hook = func;
1037 * mono_string_equal:
1038 * @s1: First string to compare
1039 * @s2: Second string to compare
1041 * Returns FALSE if the strings differ.
1044 mono_string_equal (MonoString *s1, MonoString *s2)
1046 int l1 = mono_string_length (s1);
1047 int l2 = mono_string_length (s2);
1054 return memcmp (mono_string_chars (s1), mono_string_chars (s2), l1 * 2) == 0;
1059 * @s: the string to hash
1061 * Returns the hash for the string.
1064 mono_string_hash (MonoString *s)
1066 const guint16 *p = mono_string_chars (s);
1067 int i, len = mono_string_length (s);
1070 for (i = 0; i < len; i++) {
1071 h = (h << 5) - h + *p;
1079 mono_ptrarray_equal (gpointer *s1, gpointer *s2)
1081 int len = GPOINTER_TO_INT (s1 [0]);
1082 if (len != GPOINTER_TO_INT (s2 [0]))
1085 return memcmp (s1 + 1, s2 + 1, len * sizeof(gpointer)) == 0;
1089 mono_ptrarray_hash (gpointer *s)
1092 int len = GPOINTER_TO_INT (s [0]);
1095 for (i = 1; i < len; i++)
1096 hash += GPOINTER_TO_UINT (s [i]);
1102 * Allocate an id for domain and set domain->domain_id.
1103 * LOCKING: must be called while holding appdomains_mutex.
1104 * We try to assign low numbers to the domain, so it can be used
1105 * as an index in data tables to lookup domain-specific info
1106 * with minimal memory overhead. We also try not to reuse the
1107 * same id too quickly (to help debugging).
1110 domain_id_alloc (MonoDomain *domain)
1113 if (!appdomains_list) {
1114 appdomain_list_size = 2;
1115 appdomains_list = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1117 for (i = appdomain_next; i < appdomain_list_size; ++i) {
1118 if (!appdomains_list [i]) {
1124 for (i = 0; i < appdomain_next; ++i) {
1125 if (!appdomains_list [i]) {
1132 MonoDomain **new_list;
1133 int new_size = appdomain_list_size * 2;
1134 if (new_size >= (1 << 16))
1135 g_assert_not_reached ();
1136 id = appdomain_list_size;
1137 new_list = mono_gc_alloc_fixed (new_size * sizeof (void*), NULL);
1138 memcpy (new_list, appdomains_list, appdomain_list_size * sizeof (void*));
1139 mono_gc_free_fixed (appdomains_list);
1140 appdomains_list = new_list;
1141 appdomain_list_size = new_size;
1143 domain->domain_id = id;
1144 appdomains_list [id] = domain;
1146 if (appdomain_next > appdomain_list_size)
1151 static guint32 domain_gc_bitmap [sizeof(MonoDomain)/4/32 + 1];
1152 static gpointer domain_gc_desc = NULL;
1153 static guint32 domain_shadow_serial = 0L;
1156 mono_domain_create (void)
1159 guint32 shadow_serial;
1161 mono_appdomains_lock ();
1162 shadow_serial = domain_shadow_serial++;
1164 if (!domain_gc_desc) {
1165 unsigned int i, bit = 0;
1166 for (i = G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_OBJECT); i < G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_GC_TRACKED); i += sizeof (gpointer)) {
1167 bit = i / sizeof (gpointer);
1168 domain_gc_bitmap [bit / 32] |= 1 << (bit % 32);
1170 domain_gc_desc = mono_gc_make_descr_from_bitmap ((gsize*)domain_gc_bitmap, bit + 1);
1172 mono_appdomains_unlock ();
1174 domain = mono_gc_alloc_fixed (sizeof (MonoDomain), domain_gc_desc);
1175 domain->shadow_serial = shadow_serial;
1176 domain->domain = NULL;
1177 domain->setup = NULL;
1178 domain->friendly_name = NULL;
1179 domain->search_path = NULL;
1181 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);
1183 mono_profiler_appdomain_event (domain, MONO_PROFILE_START_LOAD);
1185 domain->mp = mono_mempool_new ();
1186 domain->code_mp = mono_code_manager_new ();
1187 domain->env = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1188 domain->domain_assemblies = NULL;
1189 domain->class_vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1190 domain->proxy_vtable_hash = g_hash_table_new ((GHashFunc)mono_ptrarray_hash, (GCompareFunc)mono_ptrarray_equal);
1191 domain->static_data_array = NULL;
1192 mono_jit_code_hash_init (&domain->jit_code_hash);
1193 domain->ldstr_table = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1194 domain->num_jit_info_tables = 1;
1195 domain->jit_info_table = jit_info_table_new (domain);
1196 domain->jit_info_free_queue = NULL;
1197 domain->finalizable_objects_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1198 #ifndef HAVE_SGEN_GC
1199 domain->track_resurrection_handles_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1202 InitializeCriticalSection (&domain->lock);
1203 InitializeCriticalSection (&domain->assemblies_lock);
1204 InitializeCriticalSection (&domain->jit_code_hash_lock);
1205 InitializeCriticalSection (&domain->finalizable_objects_hash_lock);
1207 domain->method_rgctx_hash = NULL;
1209 mono_appdomains_lock ();
1210 domain_id_alloc (domain);
1211 mono_appdomains_unlock ();
1213 mono_perfcounters->loader_appdomains++;
1214 mono_perfcounters->loader_total_appdomains++;
1216 mono_debug_domain_create (domain);
1218 if (create_domain_hook)
1219 create_domain_hook (domain);
1221 mono_profiler_appdomain_loaded (domain, MONO_PROFILE_OK);
1227 * mono_init_internal:
1229 * Creates the initial application domain and initializes the mono_defaults
1231 * This function is guaranteed to not run any IL code.
1232 * If exe_filename is not NULL, the method will determine the required runtime
1233 * from the exe configuration file or the version PE field.
1234 * If runtime_version is not NULL, that runtime version will be used.
1235 * Either exe_filename or runtime_version must be provided.
1237 * Returns: the initial domain.
1240 mono_init_internal (const char *filename, const char *exe_filename, const char *runtime_version)
1242 static MonoDomain *domain = NULL;
1243 MonoAssembly *ass = NULL;
1244 MonoImageOpenStatus status = MONO_IMAGE_OK;
1245 const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
1249 g_assert_not_reached ();
1252 /* Avoid system error message boxes. */
1253 SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1255 mono_load_coree (exe_filename);
1258 mono_perfcounters_init ();
1260 mono_counters_register ("Max native code in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_size);
1261 mono_counters_register ("Max code space allocated in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_alloc);
1262 mono_counters_register ("Total code space allocated", MONO_COUNTER_INT|MONO_COUNTER_JIT, &total_domain_code_alloc);
1264 mono_gc_base_init ();
1266 appdomain_thread_id = TlsAlloc ();
1268 InitializeCriticalSection (&appdomains_mutex);
1270 mono_metadata_init ();
1271 mono_images_init ();
1272 mono_assemblies_init ();
1273 mono_classes_init ();
1274 mono_loader_init ();
1275 mono_reflection_init ();
1277 /* FIXME: When should we release this memory? */
1278 MONO_GC_REGISTER_ROOT (appdomains_list);
1280 domain = mono_domain_create ();
1281 mono_root_domain = domain;
1283 SET_APPDOMAIN (domain);
1285 /* Get a list of runtimes supported by the exe */
1286 if (exe_filename != NULL) {
1288 * This function will load the exe file as a MonoImage. We need to close it, but
1289 * that would mean it would be reloaded later. So instead, we save it to
1290 * exe_image, and close it during shutdown.
1292 get_runtimes_from_exe (exe_filename, &exe_image, runtimes);
1295 exe_image = mono_assembly_open_from_bundle (exe_filename, NULL, FALSE);
1297 exe_image = mono_image_open (exe_filename, NULL);
1299 mono_fixup_exe_image (exe_image);
1301 } else if (runtime_version != NULL) {
1302 runtimes [0] = get_runtime_by_version (runtime_version);
1303 runtimes [1] = NULL;
1306 if (runtimes [0] == NULL) {
1307 const MonoRuntimeInfo *default_runtime = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
1308 runtimes [0] = default_runtime;
1309 runtimes [1] = NULL;
1310 g_print ("WARNING: The runtime version supported by this application is unavailable.\n");
1311 g_print ("Using default runtime: %s\n", default_runtime->runtime_version);
1314 /* The selected runtime will be the first one for which there is a mscrolib.dll */
1315 for (n = 0; runtimes [n] != NULL && ass == NULL; n++) {
1316 current_runtime = runtimes [n];
1317 ass = mono_assembly_load_corlib (current_runtime, &status);
1318 if (status != MONO_IMAGE_OK && status != MONO_IMAGE_ERROR_ERRNO)
1323 /* Now that we have a runtime, set the policy for unhandled exceptions */
1324 if (mono_framework_version () < 2) {
1325 mono_runtime_unhandled_exception_policy_set (MONO_UNHANDLED_POLICY_LEGACY);
1328 if ((status != MONO_IMAGE_OK) || (ass == NULL)) {
1330 case MONO_IMAGE_ERROR_ERRNO: {
1331 char *corlib_file = g_build_filename (mono_assembly_getrootdir (), "mono", current_runtime->framework_version, "mscorlib.dll", NULL);
1332 g_print ("The assembly mscorlib.dll was not found or could not be loaded.\n");
1333 g_print ("It should have been installed in the `%s' directory.\n", corlib_file);
1334 g_free (corlib_file);
1337 case MONO_IMAGE_IMAGE_INVALID:
1338 g_print ("The file %s/mscorlib.dll is an invalid CIL image\n",
1339 mono_assembly_getrootdir ());
1341 case MONO_IMAGE_MISSING_ASSEMBLYREF:
1342 g_print ("Missing assembly reference in %s/mscorlib.dll\n",
1343 mono_assembly_getrootdir ());
1346 /* to suppress compiler warning */
1352 mono_defaults.corlib = mono_assembly_get_image (ass);
1354 mono_defaults.object_class = mono_class_from_name (
1355 mono_defaults.corlib, "System", "Object");
1356 g_assert (mono_defaults.object_class != 0);
1358 mono_defaults.void_class = mono_class_from_name (
1359 mono_defaults.corlib, "System", "Void");
1360 g_assert (mono_defaults.void_class != 0);
1362 mono_defaults.boolean_class = mono_class_from_name (
1363 mono_defaults.corlib, "System", "Boolean");
1364 g_assert (mono_defaults.boolean_class != 0);
1366 mono_defaults.byte_class = mono_class_from_name (
1367 mono_defaults.corlib, "System", "Byte");
1368 g_assert (mono_defaults.byte_class != 0);
1370 mono_defaults.sbyte_class = mono_class_from_name (
1371 mono_defaults.corlib, "System", "SByte");
1372 g_assert (mono_defaults.sbyte_class != 0);
1374 mono_defaults.int16_class = mono_class_from_name (
1375 mono_defaults.corlib, "System", "Int16");
1376 g_assert (mono_defaults.int16_class != 0);
1378 mono_defaults.uint16_class = mono_class_from_name (
1379 mono_defaults.corlib, "System", "UInt16");
1380 g_assert (mono_defaults.uint16_class != 0);
1382 mono_defaults.int32_class = mono_class_from_name (
1383 mono_defaults.corlib, "System", "Int32");
1384 g_assert (mono_defaults.int32_class != 0);
1386 mono_defaults.uint32_class = mono_class_from_name (
1387 mono_defaults.corlib, "System", "UInt32");
1388 g_assert (mono_defaults.uint32_class != 0);
1390 mono_defaults.uint_class = mono_class_from_name (
1391 mono_defaults.corlib, "System", "UIntPtr");
1392 g_assert (mono_defaults.uint_class != 0);
1394 mono_defaults.int_class = mono_class_from_name (
1395 mono_defaults.corlib, "System", "IntPtr");
1396 g_assert (mono_defaults.int_class != 0);
1398 mono_defaults.int64_class = mono_class_from_name (
1399 mono_defaults.corlib, "System", "Int64");
1400 g_assert (mono_defaults.int64_class != 0);
1402 mono_defaults.uint64_class = mono_class_from_name (
1403 mono_defaults.corlib, "System", "UInt64");
1404 g_assert (mono_defaults.uint64_class != 0);
1406 mono_defaults.single_class = mono_class_from_name (
1407 mono_defaults.corlib, "System", "Single");
1408 g_assert (mono_defaults.single_class != 0);
1410 mono_defaults.double_class = mono_class_from_name (
1411 mono_defaults.corlib, "System", "Double");
1412 g_assert (mono_defaults.double_class != 0);
1414 mono_defaults.char_class = mono_class_from_name (
1415 mono_defaults.corlib, "System", "Char");
1416 g_assert (mono_defaults.char_class != 0);
1418 mono_defaults.string_class = mono_class_from_name (
1419 mono_defaults.corlib, "System", "String");
1420 g_assert (mono_defaults.string_class != 0);
1422 mono_defaults.enum_class = mono_class_from_name (
1423 mono_defaults.corlib, "System", "Enum");
1424 g_assert (mono_defaults.enum_class != 0);
1426 mono_defaults.array_class = mono_class_from_name (
1427 mono_defaults.corlib, "System", "Array");
1428 g_assert (mono_defaults.array_class != 0);
1430 mono_defaults.delegate_class = mono_class_from_name (
1431 mono_defaults.corlib, "System", "Delegate");
1432 g_assert (mono_defaults.delegate_class != 0 );
1434 mono_defaults.multicastdelegate_class = mono_class_from_name (
1435 mono_defaults.corlib, "System", "MulticastDelegate");
1436 g_assert (mono_defaults.multicastdelegate_class != 0 );
1438 mono_defaults.asyncresult_class = mono_class_from_name (
1439 mono_defaults.corlib, "System.Runtime.Remoting.Messaging",
1441 g_assert (mono_defaults.asyncresult_class != 0 );
1443 mono_defaults.manualresetevent_class = mono_class_from_name (
1444 mono_defaults.corlib, "System.Threading", "ManualResetEvent");
1445 g_assert (mono_defaults.manualresetevent_class != 0 );
1447 mono_defaults.typehandle_class = mono_class_from_name (
1448 mono_defaults.corlib, "System", "RuntimeTypeHandle");
1449 g_assert (mono_defaults.typehandle_class != 0);
1451 mono_defaults.methodhandle_class = mono_class_from_name (
1452 mono_defaults.corlib, "System", "RuntimeMethodHandle");
1453 g_assert (mono_defaults.methodhandle_class != 0);
1455 mono_defaults.fieldhandle_class = mono_class_from_name (
1456 mono_defaults.corlib, "System", "RuntimeFieldHandle");
1457 g_assert (mono_defaults.fieldhandle_class != 0);
1459 mono_defaults.systemtype_class = mono_class_from_name (
1460 mono_defaults.corlib, "System", "Type");
1461 g_assert (mono_defaults.systemtype_class != 0);
1463 mono_defaults.monotype_class = mono_class_from_name (
1464 mono_defaults.corlib, "System", "MonoType");
1465 g_assert (mono_defaults.monotype_class != 0);
1467 mono_defaults.exception_class = mono_class_from_name (
1468 mono_defaults.corlib, "System", "Exception");
1469 g_assert (mono_defaults.exception_class != 0);
1471 mono_defaults.threadabortexception_class = mono_class_from_name (
1472 mono_defaults.corlib, "System.Threading", "ThreadAbortException");
1473 g_assert (mono_defaults.threadabortexception_class != 0);
1475 mono_defaults.thread_class = mono_class_from_name (
1476 mono_defaults.corlib, "System.Threading", "Thread");
1477 g_assert (mono_defaults.thread_class != 0);
1479 mono_defaults.internal_thread_class = mono_class_from_name (
1480 mono_defaults.corlib, "System.Threading", "InternalThread");
1481 if (!mono_defaults.internal_thread_class) {
1482 /* This can happen with an old mscorlib */
1483 fprintf (stderr, "Corlib too old for this runtime.\n");
1484 fprintf (stderr, "Loaded from: %s\n",
1485 mono_defaults.corlib? mono_image_get_filename (mono_defaults.corlib): "unknown");
1489 mono_defaults.appdomain_class = mono_class_from_name (
1490 mono_defaults.corlib, "System", "AppDomain");
1491 g_assert (mono_defaults.appdomain_class != 0);
1493 mono_defaults.transparent_proxy_class = mono_class_from_name (
1494 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "TransparentProxy");
1495 g_assert (mono_defaults.transparent_proxy_class != 0);
1497 mono_defaults.real_proxy_class = mono_class_from_name (
1498 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "RealProxy");
1499 g_assert (mono_defaults.real_proxy_class != 0);
1501 mono_defaults.mono_method_message_class = mono_class_from_name (
1502 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", "MonoMethodMessage");
1503 g_assert (mono_defaults.mono_method_message_class != 0);
1505 mono_defaults.field_info_class = mono_class_from_name (
1506 mono_defaults.corlib, "System.Reflection", "FieldInfo");
1507 g_assert (mono_defaults.field_info_class != 0);
1509 mono_defaults.method_info_class = mono_class_from_name (
1510 mono_defaults.corlib, "System.Reflection", "MethodInfo");
1511 g_assert (mono_defaults.method_info_class != 0);
1513 mono_defaults.stringbuilder_class = mono_class_from_name (
1514 mono_defaults.corlib, "System.Text", "StringBuilder");
1515 g_assert (mono_defaults.stringbuilder_class != 0);
1517 mono_defaults.math_class = mono_class_from_name (
1518 mono_defaults.corlib, "System", "Math");
1519 g_assert (mono_defaults.math_class != 0);
1521 mono_defaults.stack_frame_class = mono_class_from_name (
1522 mono_defaults.corlib, "System.Diagnostics", "StackFrame");
1523 g_assert (mono_defaults.stack_frame_class != 0);
1525 mono_defaults.stack_trace_class = mono_class_from_name (
1526 mono_defaults.corlib, "System.Diagnostics", "StackTrace");
1527 g_assert (mono_defaults.stack_trace_class != 0);
1529 mono_defaults.marshal_class = mono_class_from_name (
1530 mono_defaults.corlib, "System.Runtime.InteropServices", "Marshal");
1531 g_assert (mono_defaults.marshal_class != 0);
1533 mono_defaults.iserializeable_class = mono_class_from_name (
1534 mono_defaults.corlib, "System.Runtime.Serialization", "ISerializable");
1535 g_assert (mono_defaults.iserializeable_class != 0);
1537 mono_defaults.serializationinfo_class = mono_class_from_name (
1538 mono_defaults.corlib, "System.Runtime.Serialization", "SerializationInfo");
1539 g_assert (mono_defaults.serializationinfo_class != 0);
1541 mono_defaults.streamingcontext_class = mono_class_from_name (
1542 mono_defaults.corlib, "System.Runtime.Serialization", "StreamingContext");
1543 g_assert (mono_defaults.streamingcontext_class != 0);
1545 mono_defaults.typed_reference_class = mono_class_from_name (
1546 mono_defaults.corlib, "System", "TypedReference");
1547 g_assert (mono_defaults.typed_reference_class != 0);
1549 mono_defaults.argumenthandle_class = mono_class_from_name (
1550 mono_defaults.corlib, "System", "RuntimeArgumentHandle");
1551 g_assert (mono_defaults.argumenthandle_class != 0);
1553 mono_defaults.marshalbyrefobject_class = mono_class_from_name (
1554 mono_defaults.corlib, "System", "MarshalByRefObject");
1555 g_assert (mono_defaults.marshalbyrefobject_class != 0);
1557 mono_defaults.monitor_class = mono_class_from_name (
1558 mono_defaults.corlib, "System.Threading", "Monitor");
1559 g_assert (mono_defaults.monitor_class != 0);
1561 mono_defaults.iremotingtypeinfo_class = mono_class_from_name (
1562 mono_defaults.corlib, "System.Runtime.Remoting", "IRemotingTypeInfo");
1563 g_assert (mono_defaults.iremotingtypeinfo_class != 0);
1565 mono_defaults.runtimesecurityframe_class = mono_class_from_name (
1566 mono_defaults.corlib, "System.Security", "RuntimeSecurityFrame");
1568 mono_defaults.executioncontext_class = mono_class_from_name (
1569 mono_defaults.corlib, "System.Threading", "ExecutionContext");
1571 mono_defaults.internals_visible_class = mono_class_from_name (
1572 mono_defaults.corlib, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute");
1574 mono_defaults.critical_finalizer_object = mono_class_from_name (
1575 mono_defaults.corlib, "System.Runtime.ConstrainedExecution", "CriticalFinalizerObject");
1578 * mscorlib needs a little help, only now it can load its friends list (after we have
1579 * loaded the InternalsVisibleToAttribute), load it now
1581 mono_assembly_load_friends (ass);
1583 mono_defaults.safehandle_class = mono_class_from_name (
1584 mono_defaults.corlib, "System.Runtime.InteropServices", "SafeHandle");
1586 mono_defaults.handleref_class = mono_class_from_name (
1587 mono_defaults.corlib, "System.Runtime.InteropServices", "HandleRef");
1589 mono_defaults.attribute_class = mono_class_from_name (
1590 mono_defaults.corlib, "System", "Attribute");
1592 mono_defaults.customattribute_data_class = mono_class_from_name (
1593 mono_defaults.corlib, "System.Reflection", "CustomAttributeData");
1595 /* these are initialized lazily when COM features are used */
1596 mono_defaults.variant_class = NULL;
1597 mono_defaults.com_object_class = NULL;
1598 mono_defaults.com_interop_proxy_class = NULL;
1599 mono_defaults.iunknown_class = NULL;
1600 mono_defaults.idispatch_class = NULL;
1603 * Note that mono_defaults.generic_*_class is only non-NULL if we're
1604 * using the 2.0 corlib.
1606 mono_class_init (mono_defaults.array_class);
1607 mono_defaults.generic_nullable_class = mono_class_from_name (
1608 mono_defaults.corlib, "System", "Nullable`1");
1609 mono_defaults.generic_ilist_class = mono_class_from_name (
1610 mono_defaults.corlib, "System.Collections.Generic", "IList`1");
1612 domain->friendly_name = g_path_get_basename (filename);
1614 _mono_debug_init_corlib (domain);
1622 * Creates the initial application domain and initializes the mono_defaults
1624 * This function is guaranteed to not run any IL code.
1625 * The runtime is initialized using the default runtime version.
1627 * Returns: the initial domain.
1630 mono_init (const char *domain_name)
1632 return mono_init_internal (domain_name, NULL, DEFAULT_RUNTIME_VERSION);
1636 * mono_init_from_assembly:
1638 * Creates the initial application domain and initializes the mono_defaults
1640 * This function is guaranteed to not run any IL code.
1641 * The runtime is initialized using the runtime version required by the
1642 * provided executable. The version is determined by looking at the exe
1643 * configuration file and the version PE field)
1645 * Returns: the initial domain.
1648 mono_init_from_assembly (const char *domain_name, const char *filename)
1650 return mono_init_internal (domain_name, filename, NULL);
1654 * mono_init_version:
1656 * Creates the initial application domain and initializes the mono_defaults
1658 * This function is guaranteed to not run any IL code.
1659 * The runtime is initialized using the provided rutime version.
1661 * Returns: the initial domain.
1664 mono_init_version (const char *domain_name, const char *version)
1666 return mono_init_internal (domain_name, NULL, version);
1670 * mono_init_com_types:
1672 * Initializes all types needed for COM Interop in mono_defaults structure.
1675 mono_init_com_types (void)
1677 static gboolean initialized = FALSE;
1682 /* FIXME: do I need some threading protection here */
1684 g_assert (mono_defaults.corlib);
1686 mono_defaults.variant_class = mono_class_from_name (
1687 mono_defaults.corlib, "System", "Variant");
1688 g_assert (mono_defaults.variant_class != 0);
1690 mono_defaults.com_object_class = mono_class_from_name (
1691 mono_defaults.corlib, "System", "__ComObject");
1692 g_assert (mono_defaults.com_object_class != 0);
1694 mono_defaults.com_interop_proxy_class = mono_class_from_name (
1695 mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
1696 g_assert (mono_defaults.com_interop_proxy_class != 0);
1698 mono_defaults.iunknown_class = mono_class_from_name (
1699 mono_defaults.corlib, "Mono.Interop", "IUnknown");
1700 g_assert (mono_defaults.iunknown_class != 0);
1702 mono_defaults.idispatch_class = mono_class_from_name (
1703 mono_defaults.corlib, "Mono.Interop", "IDispatch");
1704 g_assert (mono_defaults.idispatch_class != 0);
1712 * Cleans up all metadata modules.
1717 mono_close_exe_image ();
1719 mono_loader_cleanup ();
1720 mono_classes_cleanup ();
1721 mono_assemblies_cleanup ();
1722 mono_images_cleanup ();
1723 mono_debug_cleanup ();
1724 mono_metadata_cleanup ();
1726 TlsFree (appdomain_thread_id);
1727 DeleteCriticalSection (&appdomains_mutex);
1731 mono_close_exe_image (void)
1734 mono_image_close (exe_image);
1738 * mono_get_root_domain:
1740 * The root AppDomain is the initial domain created by the runtime when it is
1741 * initialized. Programs execute on this AppDomain, but can create new ones
1742 * later. Currently there is no unmanaged API to create new AppDomains, this
1743 * must be done from managed code.
1745 * Returns: the root appdomain, to obtain the current domain, use mono_domain_get ()
1748 mono_get_root_domain (void)
1750 return mono_root_domain;
1756 * Returns: the current domain, to obtain the root domain use
1757 * mono_get_root_domain().
1762 return GET_APPDOMAIN ();
1766 mono_domain_unset (void)
1768 SET_APPDOMAIN (NULL);
1772 mono_domain_set_internal_with_options (MonoDomain *domain, gboolean migrate_exception)
1774 MonoInternalThread *thread;
1776 if (mono_domain_get () == domain)
1779 SET_APPDOMAIN (domain);
1780 SET_APPCONTEXT (domain->default_context);
1782 if (migrate_exception) {
1783 thread = mono_thread_internal_current ();
1784 if (!thread->abort_exc)
1787 g_assert (thread->abort_exc->object.vtable->domain != domain);
1788 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
1789 g_assert (thread->abort_exc->object.vtable->domain == domain);
1794 * mono_domain_set_internal:
1795 * @domain: the new domain
1797 * Sets the current domain to @domain.
1800 mono_domain_set_internal (MonoDomain *domain)
1802 mono_domain_set_internal_with_options (domain, TRUE);
1806 mono_domain_foreach (MonoDomainFunc func, gpointer user_data)
1812 * Create a copy of the data to avoid calling the user callback
1813 * inside the lock because that could lead to deadlocks.
1814 * We can do this because this function is not perf. critical.
1816 mono_appdomains_lock ();
1817 size = appdomain_list_size;
1818 copy = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1819 memcpy (copy, appdomains_list, appdomain_list_size * sizeof (void*));
1820 mono_appdomains_unlock ();
1822 for (i = 0; i < size; ++i) {
1824 func (copy [i], user_data);
1827 mono_gc_free_fixed (copy);
1831 * mono_domain_assembly_open:
1832 * @domain: the application domain
1833 * @name: file name of the assembly
1835 * fixme: maybe we should integrate this with mono_assembly_open ??
1838 mono_domain_assembly_open (MonoDomain *domain, const char *name)
1840 MonoDomain *current;
1844 mono_domain_assemblies_lock (domain);
1845 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1847 if (strcmp (name, ass->aname.name) == 0) {
1848 mono_domain_assemblies_unlock (domain);
1852 mono_domain_assemblies_unlock (domain);
1854 if (domain != mono_domain_get ()) {
1855 current = mono_domain_get ();
1857 mono_domain_set (domain, FALSE);
1858 ass = mono_assembly_open (name, NULL);
1859 mono_domain_set (current, FALSE);
1861 ass = mono_assembly_open (name, NULL);
1867 #ifndef HAVE_SGEN_GC
1869 free_slist (gpointer key, gpointer value, gpointer user_data)
1871 g_slist_free (value);
1877 unregister_vtable_reflection_type (gpointer key, gpointer value, gpointer user_data)
1879 MonoVTable *vtable = value;
1880 MonoObject *type = vtable->type;
1882 if (type->vtable->klass != mono_defaults.monotype_class)
1883 mono_gc_deregister_root ((char*)&vtable->type);
1888 mono_domain_free (MonoDomain *domain, gboolean force)
1890 int code_size, code_alloc;
1892 if ((domain == mono_root_domain) && !force) {
1893 g_warning ("cant unload root domain");
1897 if (mono_dont_free_domains)
1900 mono_profiler_appdomain_event (domain, MONO_PROFILE_START_UNLOAD);
1902 mono_debug_domain_unload (domain);
1904 mono_appdomains_lock ();
1905 appdomains_list [domain->domain_id] = NULL;
1906 mono_appdomains_unlock ();
1908 /* must do this early as it accesses fields and types */
1909 if (domain->special_static_fields) {
1910 mono_alloc_special_static_data_free (domain->special_static_fields);
1911 g_hash_table_destroy (domain->special_static_fields);
1912 domain->special_static_fields = NULL;
1916 * We must destroy all these hash tables here because they
1917 * contain references to managed objects belonging to the
1918 * domain. Once we let the GC clear the domain there must be
1919 * no more such references, or we'll crash if a collection
1922 mono_g_hash_table_destroy (domain->ldstr_table);
1923 domain->ldstr_table = NULL;
1925 mono_g_hash_table_destroy (domain->env);
1928 mono_reflection_cleanup_domain (domain);
1930 if (domain->type_hash) {
1931 mono_g_hash_table_destroy (domain->type_hash);
1932 domain->type_hash = NULL;
1934 if (domain->type_init_exception_hash) {
1935 mono_g_hash_table_destroy (domain->type_init_exception_hash);
1936 domain->type_init_exception_hash = NULL;
1939 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1940 MonoAssembly *ass = tmp->data;
1941 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading domain %s %p, assembly %s %p, refcount=%d\n", domain->friendly_name, domain, ass->aname.name, ass, ass->ref_count);
1942 if (!mono_assembly_close_except_image_pools (ass))
1947 if (domain->class_vtable_hash)
1948 g_hash_table_foreach (domain->class_vtable_hash, unregister_vtable_reflection_type, NULL);
1951 mono_gc_clear_domain (domain);
1953 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1954 MonoAssembly *ass = tmp->data;
1956 mono_assembly_close_finish (ass);
1958 g_slist_free (domain->domain_assemblies);
1959 domain->domain_assemblies = NULL;
1962 * Send this after the assemblies have been unloaded and the domain is still in a
1965 mono_profiler_appdomain_event (domain, MONO_PROFILE_END_UNLOAD);
1967 if (free_domain_hook)
1968 free_domain_hook (domain);
1970 /* FIXME: free delegate_hash_table when it's used */
1971 if (domain->search_path) {
1972 g_strfreev (domain->search_path);
1973 domain->search_path = NULL;
1975 domain->create_proxy_for_type_method = NULL;
1976 domain->private_invoke_method = NULL;
1977 domain->default_context = NULL;
1978 domain->out_of_memory_ex = NULL;
1979 domain->null_reference_ex = NULL;
1980 domain->stack_overflow_ex = NULL;
1981 domain->entry_assembly = NULL;
1983 g_free (domain->friendly_name);
1984 domain->friendly_name = NULL;
1985 g_hash_table_destroy (domain->class_vtable_hash);
1986 domain->class_vtable_hash = NULL;
1987 g_hash_table_destroy (domain->proxy_vtable_hash);
1988 domain->proxy_vtable_hash = NULL;
1989 if (domain->static_data_array) {
1990 mono_gc_free_fixed (domain->static_data_array);
1991 domain->static_data_array = NULL;
1993 mono_internal_hash_table_destroy (&domain->jit_code_hash);
1996 * There might still be jit info tables of this domain which
1997 * are not freed. Since the domain cannot be in use anymore,
1998 * this will free them.
2000 mono_thread_hazardous_try_free_all ();
2001 g_assert (domain->num_jit_info_tables == 1);
2002 jit_info_table_free (domain->jit_info_table);
2003 domain->jit_info_table = NULL;
2004 g_assert (!domain->jit_info_free_queue);
2006 /* collect statistics */
2007 code_alloc = mono_code_manager_size (domain->code_mp, &code_size);
2008 total_domain_code_alloc += code_alloc;
2009 max_domain_code_alloc = MAX (max_domain_code_alloc, code_alloc);
2010 max_domain_code_size = MAX (max_domain_code_size, code_size);
2012 #ifdef DEBUG_DOMAIN_UNLOAD
2013 mono_mempool_invalidate (domain->mp);
2014 mono_code_manager_invalidate (domain->code_mp);
2016 mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (domain->mp);
2017 mono_mempool_destroy (domain->mp);
2019 mono_code_manager_destroy (domain->code_mp);
2020 domain->code_mp = NULL;
2023 g_hash_table_destroy (domain->finalizable_objects_hash);
2024 domain->finalizable_objects_hash = NULL;
2025 #ifndef HAVE_SGEN_GC
2026 if (domain->track_resurrection_objects_hash) {
2027 g_hash_table_foreach (domain->track_resurrection_objects_hash, free_slist, NULL);
2028 g_hash_table_destroy (domain->track_resurrection_objects_hash);
2030 if (domain->track_resurrection_handles_hash)
2031 g_hash_table_destroy (domain->track_resurrection_handles_hash);
2033 if (domain->method_rgctx_hash) {
2034 g_hash_table_destroy (domain->method_rgctx_hash);
2035 domain->method_rgctx_hash = NULL;
2037 if (domain->generic_virtual_cases) {
2038 g_hash_table_destroy (domain->generic_virtual_cases);
2039 domain->generic_virtual_cases = NULL;
2042 DeleteCriticalSection (&domain->finalizable_objects_hash_lock);
2043 DeleteCriticalSection (&domain->assemblies_lock);
2044 DeleteCriticalSection (&domain->jit_code_hash_lock);
2045 DeleteCriticalSection (&domain->lock);
2046 domain->setup = NULL;
2048 mono_gc_deregister_root ((char*)&(domain->MONO_DOMAIN_FIRST_GC_TRACKED));
2050 /* FIXME: anything else required ? */
2052 mono_gc_free_fixed (domain);
2054 mono_perfcounters->loader_appdomains--;
2056 if ((domain == mono_root_domain))
2057 mono_root_domain = NULL;
2061 * mono_domain_get_id:
2064 * Returns: the a domain for a specific domain id.
2067 mono_domain_get_by_id (gint32 domainid)
2069 MonoDomain * domain;
2071 mono_appdomains_lock ();
2072 if (domainid < appdomain_list_size)
2073 domain = appdomains_list [domainid];
2076 mono_appdomains_unlock ();
2082 mono_domain_get_id (MonoDomain *domain)
2084 return domain->domain_id;
2088 * mono_domain_alloc:
2090 * LOCKING: Acquires the domain lock.
2093 mono_domain_alloc (MonoDomain *domain, guint size)
2097 mono_domain_lock (domain);
2098 mono_perfcounters->loader_bytes += size;
2099 res = mono_mempool_alloc (domain->mp, size);
2100 mono_domain_unlock (domain);
2106 * mono_domain_alloc0:
2108 * LOCKING: Acquires the domain lock.
2111 mono_domain_alloc0 (MonoDomain *domain, guint size)
2115 mono_domain_lock (domain);
2116 mono_perfcounters->loader_bytes += size;
2117 res = mono_mempool_alloc0 (domain->mp, size);
2118 mono_domain_unlock (domain);
2124 * mono_domain_code_reserve:
2126 * LOCKING: Acquires the domain lock.
2129 mono_domain_code_reserve (MonoDomain *domain, int size)
2133 mono_domain_lock (domain);
2134 res = mono_code_manager_reserve (domain->code_mp, size);
2135 mono_domain_unlock (domain);
2141 * mono_domain_code_reserve_align:
2143 * LOCKING: Acquires the domain lock.
2146 mono_domain_code_reserve_align (MonoDomain *domain, int size, int alignment)
2150 mono_domain_lock (domain);
2151 res = mono_code_manager_reserve_align (domain->code_mp, size, alignment);
2152 mono_domain_unlock (domain);
2158 * mono_domain_code_commit:
2160 * LOCKING: Acquires the domain lock.
2163 mono_domain_code_commit (MonoDomain *domain, void *data, int size, int newsize)
2165 mono_domain_lock (domain);
2166 mono_code_manager_commit (domain->code_mp, data, size, newsize);
2167 mono_domain_unlock (domain);
2171 * mono_domain_code_foreach:
2172 * Iterate over the code thunks of the code manager of @domain.
2174 * The @func callback MUST not take any locks. If it really needs to, it must respect
2175 * the locking rules of the runtime: http://www.mono-project.com/Mono:Runtime:Documentation:ThreadSafety
2176 * LOCKING: Acquires the domain lock.
2180 mono_domain_code_foreach (MonoDomain *domain, MonoCodeManagerFunc func, void *user_data)
2182 mono_domain_lock (domain);
2183 mono_code_manager_foreach (domain->code_mp, func, user_data);
2184 mono_domain_unlock (domain);
2189 mono_context_set (MonoAppContext * new_context)
2191 SET_APPCONTEXT (new_context);
2195 mono_context_get (void)
2197 return GET_APPCONTEXT ();
2200 /* LOCKING: the caller holds the lock for this domain */
2202 mono_domain_add_class_static_data (MonoDomain *domain, MonoClass *klass, gpointer data, guint32 *bitmap)
2204 /* The first entry in the array is the index of the next free slot
2205 * and the total size of the array
2208 if (domain->static_data_array) {
2209 int size = GPOINTER_TO_INT (domain->static_data_array [1]);
2210 next = GPOINTER_TO_INT (domain->static_data_array [0]);
2212 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * (size * 2), NULL);
2213 memcpy (new_array, domain->static_data_array, sizeof (gpointer) * size);
2215 new_array [1] = GINT_TO_POINTER (size);
2216 mono_gc_free_fixed (domain->static_data_array);
2217 domain->static_data_array = new_array;
2221 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * size, NULL);
2223 new_array [0] = GINT_TO_POINTER (next);
2224 new_array [1] = GINT_TO_POINTER (size);
2225 domain->static_data_array = new_array;
2227 domain->static_data_array [next++] = data;
2228 domain->static_data_array [0] = GINT_TO_POINTER (next);
2232 mono_get_corlib (void)
2234 return mono_defaults.corlib;
2238 mono_get_object_class (void)
2240 return mono_defaults.object_class;
2244 mono_get_byte_class (void)
2246 return mono_defaults.byte_class;
2250 mono_get_void_class (void)
2252 return mono_defaults.void_class;
2256 mono_get_boolean_class (void)
2258 return mono_defaults.boolean_class;
2262 mono_get_sbyte_class (void)
2264 return mono_defaults.sbyte_class;
2268 mono_get_int16_class (void)
2270 return mono_defaults.int16_class;
2274 mono_get_uint16_class (void)
2276 return mono_defaults.uint16_class;
2280 mono_get_int32_class (void)
2282 return mono_defaults.int32_class;
2286 mono_get_uint32_class (void)
2288 return mono_defaults.uint32_class;
2292 mono_get_intptr_class (void)
2294 return mono_defaults.int_class;
2298 mono_get_uintptr_class (void)
2300 return mono_defaults.uint_class;
2304 mono_get_int64_class (void)
2306 return mono_defaults.int64_class;
2310 mono_get_uint64_class (void)
2312 return mono_defaults.uint64_class;
2316 mono_get_single_class (void)
2318 return mono_defaults.single_class;
2322 mono_get_double_class (void)
2324 return mono_defaults.double_class;
2328 mono_get_char_class (void)
2330 return mono_defaults.char_class;
2334 mono_get_string_class (void)
2336 return mono_defaults.string_class;
2340 mono_get_enum_class (void)
2342 return mono_defaults.enum_class;
2346 mono_get_array_class (void)
2348 return mono_defaults.array_class;
2352 mono_get_thread_class (void)
2354 return mono_defaults.thread_class;
2358 mono_get_exception_class (void)
2360 return mono_defaults.exception_class;
2364 static char* get_attribute_value (const gchar **attribute_names,
2365 const gchar **attribute_values,
2366 const char *att_name)
2369 for (n=0; attribute_names[n] != NULL; n++) {
2370 if (strcmp (attribute_names[n], att_name) == 0)
2371 return g_strdup (attribute_values[n]);
2376 static void start_element (GMarkupParseContext *context,
2377 const gchar *element_name,
2378 const gchar **attribute_names,
2379 const gchar **attribute_values,
2383 AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2385 if (strcmp (element_name, "configuration") == 0) {
2386 app_config->configuration_count++;
2389 if (strcmp (element_name, "startup") == 0) {
2390 app_config->startup_count++;
2394 if (app_config->configuration_count != 1 || app_config->startup_count != 1)
2397 if (strcmp (element_name, "requiredRuntime") == 0) {
2398 app_config->required_runtime = get_attribute_value (attribute_names, attribute_values, "version");
2399 } else if (strcmp (element_name, "supportedRuntime") == 0) {
2400 char *version = get_attribute_value (attribute_names, attribute_values, "version");
2401 app_config->supported_runtimes = g_slist_append (app_config->supported_runtimes, version);
2405 static void end_element (GMarkupParseContext *context,
2406 const gchar *element_name,
2410 AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2412 if (strcmp (element_name, "configuration") == 0) {
2413 app_config->configuration_count--;
2414 } else if (strcmp (element_name, "startup") == 0) {
2415 app_config->startup_count--;
2419 static const GMarkupParser
2428 static AppConfigInfo *
2429 app_config_parse (const char *exe_filename)
2431 AppConfigInfo *app_config;
2432 GMarkupParseContext *context;
2435 const char *bundled_config;
2436 char *config_filename;
2438 bundled_config = mono_config_string_for_assembly_file (exe_filename);
2440 if (bundled_config) {
2441 text = g_strdup (bundled_config);
2442 len = strlen (text);
2444 config_filename = g_strconcat (exe_filename, ".config", NULL);
2446 if (!g_file_get_contents (config_filename, &text, &len, NULL)) {
2447 g_free (config_filename);
2450 g_free (config_filename);
2453 app_config = g_new0 (AppConfigInfo, 1);
2455 context = g_markup_parse_context_new (&mono_parser, 0, app_config, NULL);
2456 if (g_markup_parse_context_parse (context, text, len, NULL)) {
2457 g_markup_parse_context_end_parse (context, NULL);
2459 g_markup_parse_context_free (context);
2465 app_config_free (AppConfigInfo* app_config)
2468 GSList *list = app_config->supported_runtimes;
2469 while (list != NULL) {
2470 rt = (char*)list->data;
2472 list = g_slist_next (list);
2474 g_slist_free (app_config->supported_runtimes);
2475 g_free (app_config->required_runtime);
2476 g_free (app_config);
2480 static const MonoRuntimeInfo*
2481 get_runtime_by_version (const char *version)
2484 int max = G_N_ELEMENTS (supported_runtimes);
2486 for (n=0; n<max; n++) {
2487 if (strcmp (version, supported_runtimes[n].runtime_version) == 0)
2488 return &supported_runtimes[n];
2494 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes)
2496 AppConfigInfo* app_config;
2498 const MonoRuntimeInfo* runtime = NULL;
2499 MonoImage *image = NULL;
2501 app_config = app_config_parse (exe_file);
2503 if (app_config != NULL) {
2504 /* Check supportedRuntime elements, if none is supported, fail.
2505 * If there are no such elements, look for a requiredRuntime element.
2507 if (app_config->supported_runtimes != NULL) {
2509 GSList *list = app_config->supported_runtimes;
2510 while (list != NULL) {
2511 version = (char*) list->data;
2512 runtime = get_runtime_by_version (version);
2513 if (runtime != NULL)
2514 runtimes [n++] = runtime;
2515 list = g_slist_next (list);
2517 runtimes [n] = NULL;
2518 app_config_free (app_config);
2522 /* Check the requiredRuntime element. This is for 1.0 apps only. */
2523 if (app_config->required_runtime != NULL) {
2524 runtimes [0] = get_runtime_by_version (app_config->required_runtime);
2525 runtimes [1] = NULL;
2526 app_config_free (app_config);
2529 app_config_free (app_config);
2532 /* Look for a runtime with the exact version */
2533 image = mono_assembly_open_from_bundle (exe_file, NULL, FALSE);
2536 image = mono_image_open (exe_file, NULL);
2538 if (image == NULL) {
2539 /* The image is wrong or the file was not found. In this case return
2540 * a default runtime and leave to the initialization method the work of
2541 * reporting the error.
2543 runtimes [0] = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
2544 runtimes [1] = NULL;
2550 runtimes [0] = get_runtime_by_version (image->version);
2551 runtimes [1] = NULL;
2556 * mono_get_runtime_info:
2558 * Returns: the version of the current runtime instance.
2560 const MonoRuntimeInfo*
2561 mono_get_runtime_info (void)
2563 return current_runtime;
2567 mono_debugger_check_runtime_version (const char *filename)
2569 const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
2570 const MonoRuntimeInfo *rinfo;
2573 get_runtimes_from_exe (filename, &image, runtimes);
2574 rinfo = runtimes [0];
2577 return g_strdup_printf ("Cannot get runtime version from assembly `%s'", filename);
2579 if (rinfo != current_runtime)
2580 return g_strdup_printf ("The Mono Debugger is currently using the `%s' runtime, but "
2581 "the assembly `%s' requires version `%s'", current_runtime->runtime_version,
2582 filename, rinfo->runtime_version);
2588 * mono_framework_version:
2590 * Return the major version of the framework curently executing.
2593 mono_framework_version (void)
2595 return current_runtime->framework_version [0] - '0';