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}, { 3, 5, 0, 0 } } },
132 {"v2.0.50727","2.0", { {2,0,0,0}, {8,0,0,0}, { 3, 5, 0, 0 } } },
133 {"v4.0.30128","4.0", { {4,0,0,0}, {10,0,0,0}, { 4, 0, 0, 0 } } },
134 {"v4.0.30319","4.0", { {4,0,0,0}, {10,0,0,0}, { 4, 0, 0, 0 } } },
135 {"moonlight", "2.1", { {2,0,5,0}, {9,0,0,0}, { 3, 5, 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 return appdomain_thread_id;
165 mono_domain_get_tls_offset (void)
168 MONO_THREAD_VAR_OFFSET (tls_appdomain, offset);
169 /* __asm ("jmp 1f; .section writetext, \"awx\"; 1: movl $tls_appdomain@ntpoff, %0; jmp 2f; .previous; 2:"
174 #define JIT_INFO_TABLE_FILL_RATIO_NOM 3
175 #define JIT_INFO_TABLE_FILL_RATIO_DENOM 4
176 #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)
178 #define JIT_INFO_TABLE_LOW_WATERMARK(n) ((n) / 2)
179 #define JIT_INFO_TABLE_HIGH_WATERMARK(n) ((n) * 5 / 6)
181 #define JIT_INFO_TOMBSTONE_MARKER ((MonoMethod*)NULL)
182 #define IS_JIT_INFO_TOMBSTONE(ji) ((ji)->method == JIT_INFO_TOMBSTONE_MARKER)
184 #define JIT_INFO_TABLE_HAZARD_INDEX 0
185 #define JIT_INFO_HAZARD_INDEX 1
188 jit_info_table_num_elements (MonoJitInfoTable *table)
191 int num_elements = 0;
193 for (i = 0; i < table->num_chunks; ++i) {
194 MonoJitInfoTableChunk *chunk = table->chunks [i];
195 int chunk_num_elements = chunk->num_elements;
198 for (j = 0; j < chunk_num_elements; ++j) {
199 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j]))
207 static MonoJitInfoTableChunk*
208 jit_info_table_new_chunk (void)
210 MonoJitInfoTableChunk *chunk = g_new0 (MonoJitInfoTableChunk, 1);
216 static MonoJitInfoTable *
217 jit_info_table_new (MonoDomain *domain)
219 MonoJitInfoTable *table = g_malloc0 (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*));
221 table->domain = domain;
222 table->num_chunks = 1;
223 table->chunks [0] = jit_info_table_new_chunk ();
229 jit_info_table_free (MonoJitInfoTable *table)
232 int num_chunks = table->num_chunks;
233 MonoDomain *domain = table->domain;
235 mono_domain_lock (domain);
237 table->domain->num_jit_info_tables--;
238 if (table->domain->num_jit_info_tables <= 1) {
241 for (list = table->domain->jit_info_free_queue; list; list = list->next)
244 g_slist_free (table->domain->jit_info_free_queue);
245 table->domain->jit_info_free_queue = NULL;
248 /* At this point we assume that there are no other threads
249 still accessing the table, so we don't have to worry about
250 hazardous pointers. */
252 for (i = 0; i < num_chunks; ++i) {
253 MonoJitInfoTableChunk *chunk = table->chunks [i];
257 if (--chunk->refcount > 0)
260 num_elements = chunk->num_elements;
261 for (j = 0; j < num_elements; ++j) {
262 MonoJitInfo *ji = chunk->data [j];
264 if (IS_JIT_INFO_TOMBSTONE (ji))
271 mono_domain_unlock (domain);
276 /* Can be called with hp==NULL, in which case it acts as an ordinary
277 pointer fetch. It's used that way indirectly from
278 mono_jit_info_table_add(), which doesn't have to care about hazards
279 because it holds the respective domain lock. */
281 get_hazardous_pointer (gpointer volatile *pp, MonoThreadHazardPointers *hp, int hazard_index)
286 /* Get the pointer */
288 /* If we don't have hazard pointers just return the
292 /* Make it hazardous */
293 mono_hazard_pointer_set (hp, hazard_index, p);
294 /* Check that it's still the same. If not, try
297 mono_hazard_pointer_clear (hp, hazard_index);
306 /* The jit_info_table is sorted in ascending order by the end
307 * addresses of the compiled methods. The reason why we have to do
308 * this is that once we introduce tombstones, it becomes possible for
309 * code ranges to overlap, and if we sort by code start and insert at
310 * the back of the table, we cannot guarantee that we won't overlook
313 * There are actually two possible ways to do the sorting and
314 * inserting which work with our lock-free mechanism:
316 * 1. Sort by start address and insert at the front. When looking for
317 * an entry, find the last one with a start address lower than the one
318 * you're looking for, then work your way to the front of the table.
320 * 2. Sort by end address and insert at the back. When looking for an
321 * entry, find the first one with an end address higher than the one
322 * you're looking for, then work your way to the end of the table.
324 * We chose the latter out of convenience.
327 jit_info_table_index (MonoJitInfoTable *table, gint8 *addr)
329 int left = 0, right = table->num_chunks;
331 g_assert (left < right);
334 int pos = (left + right) / 2;
335 MonoJitInfoTableChunk *chunk = table->chunks [pos];
337 if (addr < chunk->last_code_end)
341 } while (left < right);
342 g_assert (left == right);
344 if (left >= table->num_chunks)
345 return table->num_chunks - 1;
350 jit_info_table_chunk_index (MonoJitInfoTableChunk *chunk, MonoThreadHazardPointers *hp, gint8 *addr)
352 int left = 0, right = chunk->num_elements;
354 while (left < right) {
355 int pos = (left + right) / 2;
356 MonoJitInfo *ji = get_hazardous_pointer((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
357 gint8 *code_end = (gint8*)ji->code_start + ji->code_size;
364 g_assert (left == right);
370 mono_jit_info_table_find (MonoDomain *domain, char *addr)
372 MonoJitInfoTable *table;
375 MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
378 ++mono_stats.jit_info_table_lookup_count;
380 /* First we have to get the domain's jit_info_table. This is
381 complicated by the fact that a writer might substitute a
382 new table and free the old one. What the writer guarantees
383 us is that it looks at the hazard pointers after it has
384 changed the jit_info_table pointer. So, if we guard the
385 table by a hazard pointer and make sure that the pointer is
386 still there after we've made it hazardous, we don't have to
387 worry about the writer freeing the table. */
388 table = get_hazardous_pointer ((gpointer volatile*)&domain->jit_info_table, hp, JIT_INFO_TABLE_HAZARD_INDEX);
390 chunk_pos = jit_info_table_index (table, (gint8*)addr);
391 g_assert (chunk_pos < table->num_chunks);
393 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], hp, (gint8*)addr);
395 /* We now have a position that's very close to that of the
396 first element whose end address is higher than the one
397 we're looking for. If we don't have the exact position,
398 then we have a position below that one, so we'll just
399 search upward until we find our element. */
401 MonoJitInfoTableChunk *chunk = table->chunks [chunk_pos];
403 while (pos < chunk->num_elements) {
404 ji = get_hazardous_pointer ((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
408 if (IS_JIT_INFO_TOMBSTONE (ji)) {
409 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
412 if ((gint8*)addr >= (gint8*)ji->code_start
413 && (gint8*)addr < (gint8*)ji->code_start + ji->code_size) {
414 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
415 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
419 /* If we find a non-tombstone element which is already
420 beyond what we're looking for, we have to end the
422 if ((gint8*)addr < (gint8*)ji->code_start)
428 } while (chunk_pos < table->num_chunks);
434 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
435 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
439 /* Maybe its an AOT module */
440 image = mono_jit_info_find_aot_module ((guint8*)addr);
442 ji = jit_info_find_in_aot_func (domain, image, addr);
447 static G_GNUC_UNUSED void
448 jit_info_table_check (MonoJitInfoTable *table)
452 for (i = 0; i < table->num_chunks; ++i) {
453 MonoJitInfoTableChunk *chunk = table->chunks [i];
456 g_assert (chunk->refcount > 0 /* && chunk->refcount <= 8 */);
457 if (chunk->refcount > 10)
458 printf("warning: chunk refcount is %d\n", chunk->refcount);
459 g_assert (chunk->num_elements <= MONO_JIT_INFO_TABLE_CHUNK_SIZE);
461 for (j = 0; j < chunk->num_elements; ++j) {
462 MonoJitInfo *this = chunk->data [j];
465 g_assert ((gint8*)this->code_start + this->code_size <= chunk->last_code_end);
467 if (j < chunk->num_elements - 1)
468 next = chunk->data [j + 1];
469 else if (i < table->num_chunks - 1) {
472 for (k = i + 1; k < table->num_chunks; ++k)
473 if (table->chunks [k]->num_elements > 0)
476 if (k >= table->num_chunks)
479 g_assert (table->chunks [k]->num_elements > 0);
480 next = table->chunks [k]->data [0];
484 g_assert ((gint8*)this->code_start + this->code_size <= (gint8*)next->code_start + next->code_size);
489 static MonoJitInfoTable*
490 jit_info_table_realloc (MonoJitInfoTable *old)
493 int num_elements = jit_info_table_num_elements (old);
496 int new_chunk, new_element;
497 MonoJitInfoTable *new;
499 /* number of needed places for elements needed */
500 required_size = (int)((long)num_elements * JIT_INFO_TABLE_FILL_RATIO_DENOM / JIT_INFO_TABLE_FILL_RATIO_NOM);
501 num_chunks = (required_size + MONO_JIT_INFO_TABLE_CHUNK_SIZE - 1) / MONO_JIT_INFO_TABLE_CHUNK_SIZE;
503 new = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*) * num_chunks);
504 new->domain = old->domain;
505 new->num_chunks = num_chunks;
507 for (i = 0; i < num_chunks; ++i)
508 new->chunks [i] = jit_info_table_new_chunk ();
512 for (i = 0; i < old->num_chunks; ++i) {
513 MonoJitInfoTableChunk *chunk = old->chunks [i];
514 int chunk_num_elements = chunk->num_elements;
517 for (j = 0; j < chunk_num_elements; ++j) {
518 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j])) {
519 g_assert (new_chunk < num_chunks);
520 new->chunks [new_chunk]->data [new_element] = chunk->data [j];
521 if (++new_element >= JIT_INFO_TABLE_FILLED_NUM_ELEMENTS) {
522 new->chunks [new_chunk]->num_elements = new_element;
530 if (new_chunk < num_chunks) {
531 g_assert (new_chunk == num_chunks - 1);
532 new->chunks [new_chunk]->num_elements = new_element;
533 g_assert (new->chunks [new_chunk]->num_elements > 0);
536 for (i = 0; i < num_chunks; ++i) {
537 MonoJitInfoTableChunk *chunk = new->chunks [i];
538 MonoJitInfo *ji = chunk->data [chunk->num_elements - 1];
540 new->chunks [i]->last_code_end = (gint8*)ji->code_start + ji->code_size;
547 jit_info_table_split_chunk (MonoJitInfoTableChunk *chunk, MonoJitInfoTableChunk **new1p, MonoJitInfoTableChunk **new2p)
549 MonoJitInfoTableChunk *new1 = jit_info_table_new_chunk ();
550 MonoJitInfoTableChunk *new2 = jit_info_table_new_chunk ();
552 g_assert (chunk->num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE);
554 new1->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE / 2;
555 new2->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE - new1->num_elements;
557 memcpy ((void*)new1->data, (void*)chunk->data, sizeof (MonoJitInfo*) * new1->num_elements);
558 memcpy ((void*)new2->data, (void*)(chunk->data + new1->num_elements), sizeof (MonoJitInfo*) * new2->num_elements);
560 new1->last_code_end = (gint8*)new1->data [new1->num_elements - 1]->code_start
561 + new1->data [new1->num_elements - 1]->code_size;
562 new2->last_code_end = (gint8*)new2->data [new2->num_elements - 1]->code_start
563 + new2->data [new2->num_elements - 1]->code_size;
569 static MonoJitInfoTable*
570 jit_info_table_copy_and_split_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
572 MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
573 + sizeof (MonoJitInfoTableChunk*) * (table->num_chunks + 1));
576 new_table->domain = table->domain;
577 new_table->num_chunks = table->num_chunks + 1;
580 for (i = 0; i < table->num_chunks; ++i) {
581 if (table->chunks [i] == chunk) {
582 jit_info_table_split_chunk (chunk, &new_table->chunks [j], &new_table->chunks [j + 1]);
585 new_table->chunks [j] = table->chunks [i];
586 ++new_table->chunks [j]->refcount;
591 g_assert (j == new_table->num_chunks);
596 static MonoJitInfoTableChunk*
597 jit_info_table_purify_chunk (MonoJitInfoTableChunk *old)
599 MonoJitInfoTableChunk *new = jit_info_table_new_chunk ();
603 for (i = 0; i < old->num_elements; ++i) {
604 if (!IS_JIT_INFO_TOMBSTONE (old->data [i]))
605 new->data [j++] = old->data [i];
608 new->num_elements = j;
609 if (new->num_elements > 0)
610 new->last_code_end = (gint8*)new->data [j - 1]->code_start + new->data [j - 1]->code_size;
612 new->last_code_end = old->last_code_end;
617 static MonoJitInfoTable*
618 jit_info_table_copy_and_purify_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
620 MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
621 + sizeof (MonoJitInfoTableChunk*) * table->num_chunks);
624 new_table->domain = table->domain;
625 new_table->num_chunks = table->num_chunks;
628 for (i = 0; i < table->num_chunks; ++i) {
629 if (table->chunks [i] == chunk)
630 new_table->chunks [j++] = jit_info_table_purify_chunk (table->chunks [i]);
632 new_table->chunks [j] = table->chunks [i];
633 ++new_table->chunks [j]->refcount;
638 g_assert (j == new_table->num_chunks);
643 /* As we add an element to the table the case can arise that the chunk
644 * to which we need to add is already full. In that case we have to
645 * allocate a new table and do something about that chunk. We have
646 * several strategies:
648 * If the number of elements in the table is below the low watermark
649 * or above the high watermark, we reallocate the whole table.
650 * Otherwise we only concern ourselves with the overflowing chunk:
652 * If there are no tombstones in the chunk then we split the chunk in
653 * two, each half full.
655 * If the chunk does contain tombstones, we just make a new copy of
656 * the chunk without the tombstones, which will have room for at least
657 * the one element we have to add.
659 static MonoJitInfoTable*
660 jit_info_table_chunk_overflow (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
662 int num_elements = jit_info_table_num_elements (table);
665 if (num_elements < JIT_INFO_TABLE_LOW_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)
666 || num_elements > JIT_INFO_TABLE_HIGH_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)) {
667 //printf ("reallocing table\n");
668 return jit_info_table_realloc (table);
671 /* count the number of non-tombstone elements in the chunk */
673 for (i = 0; i < chunk->num_elements; ++i) {
674 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [i]))
678 if (num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
679 //printf ("splitting chunk\n");
680 return jit_info_table_copy_and_split_chunk (table, chunk);
683 //printf ("purifying chunk\n");
684 return jit_info_table_copy_and_purify_chunk (table, chunk);
687 /* We add elements to the table by first making space for them by
688 * shifting the elements at the back to the right, one at a time.
689 * This results in duplicate entries during the process, but during
690 * all the time the table is in a sorted state. Also, when an element
691 * is replaced by another one, the element that replaces it has an end
692 * address that is equal to or lower than that of the replaced
693 * element. That property is necessary to guarantee that when
694 * searching for an element we end up at a position not higher than
695 * the one we're looking for (i.e. we either find the element directly
696 * or we end up to the left of it).
699 mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
701 MonoJitInfoTable *table;
703 MonoJitInfoTableChunk *chunk;
707 g_assert (ji->method != NULL);
709 mono_domain_lock (domain);
711 ++mono_stats.jit_info_table_insert_count;
713 table = domain->jit_info_table;
716 chunk_pos = jit_info_table_index (table, (gint8*)ji->code_start + ji->code_size);
717 g_assert (chunk_pos < table->num_chunks);
718 chunk = table->chunks [chunk_pos];
720 if (chunk->num_elements >= MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
721 MonoJitInfoTable *new_table = jit_info_table_chunk_overflow (table, chunk);
723 /* Debugging code, should be removed. */
724 //jit_info_table_check (new_table);
726 domain->jit_info_table = new_table;
727 mono_memory_barrier ();
728 domain->num_jit_info_tables++;
729 mono_thread_hazardous_free_or_queue (table, (MonoHazardousFreeFunc)jit_info_table_free);
735 /* Debugging code, should be removed. */
736 //jit_info_table_check (table);
738 num_elements = chunk->num_elements;
740 pos = jit_info_table_chunk_index (chunk, NULL, (gint8*)ji->code_start + ji->code_size);
742 /* First we need to size up the chunk by one, by copying the
743 last item, or inserting the first one, if the table is
745 if (num_elements > 0)
746 chunk->data [num_elements] = chunk->data [num_elements - 1];
748 chunk->data [0] = ji;
749 mono_memory_write_barrier ();
750 chunk->num_elements = ++num_elements;
752 /* Shift the elements up one by one. */
753 for (i = num_elements - 2; i >= pos; --i) {
754 mono_memory_write_barrier ();
755 chunk->data [i + 1] = chunk->data [i];
758 /* Now we have room and can insert the new item. */
759 mono_memory_write_barrier ();
760 chunk->data [pos] = ji;
762 /* Set the high code end address chunk entry. */
763 chunk->last_code_end = (gint8*)chunk->data [chunk->num_elements - 1]->code_start
764 + chunk->data [chunk->num_elements - 1]->code_size;
766 /* Debugging code, should be removed. */
767 //jit_info_table_check (table);
769 mono_domain_unlock (domain);
773 mono_jit_info_make_tombstone (MonoJitInfo *ji)
775 MonoJitInfo *tombstone = g_new0 (MonoJitInfo, 1);
777 tombstone->code_start = ji->code_start;
778 tombstone->code_size = ji->code_size;
779 tombstone->method = JIT_INFO_TOMBSTONE_MARKER;
785 * LOCKING: domain lock
788 mono_jit_info_free_or_queue (MonoDomain *domain, MonoJitInfo *ji)
790 if (domain->num_jit_info_tables <= 1) {
791 /* Can it actually happen that we only have one table
792 but ji is still hazardous? */
793 mono_thread_hazardous_free_or_queue (ji, g_free);
795 domain->jit_info_free_queue = g_slist_prepend (domain->jit_info_free_queue, ji);
800 mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
802 MonoJitInfoTable *table;
803 MonoJitInfoTableChunk *chunk;
804 gpointer start = ji->code_start;
807 mono_domain_lock (domain);
808 table = domain->jit_info_table;
810 ++mono_stats.jit_info_table_remove_count;
812 chunk_pos = jit_info_table_index (table, start);
813 g_assert (chunk_pos < table->num_chunks);
815 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], NULL, start);
818 chunk = table->chunks [chunk_pos];
820 while (pos < chunk->num_elements) {
821 if (chunk->data [pos] == ji)
824 g_assert (IS_JIT_INFO_TOMBSTONE (chunk->data [pos]));
825 g_assert ((guint8*)chunk->data [pos]->code_start + chunk->data [pos]->code_size
826 <= (guint8*)ji->code_start + ji->code_size);
833 } while (chunk_pos < table->num_chunks);
836 g_assert (chunk->data [pos] == ji);
838 chunk->data [pos] = mono_jit_info_make_tombstone (ji);
840 /* Debugging code, should be removed. */
841 //jit_info_table_check (table);
843 mono_jit_info_free_or_queue (domain, ji);
845 mono_domain_unlock (domain);
848 static MonoAotModuleInfoTable*
849 mono_aot_module_info_table_new (void)
851 return g_array_new (FALSE, FALSE, sizeof (gpointer));
855 aot_info_table_index (MonoAotModuleInfoTable *table, char *addr)
857 int left = 0, right = table->len;
859 while (left < right) {
860 int pos = (left + right) / 2;
861 AotModuleInfo *ainfo = g_array_index (table, gpointer, pos);
862 char *start = ainfo->start;
863 char *end = ainfo->end;
867 else if (addr >= end)
877 mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
879 AotModuleInfo *ainfo = g_new0 (AotModuleInfo, 1);
882 ainfo->image = image;
883 ainfo->start = start;
886 mono_appdomains_lock ();
889 aot_modules = mono_aot_module_info_table_new ();
891 pos = aot_info_table_index (aot_modules, start);
893 g_array_insert_val (aot_modules, pos, ainfo);
895 mono_appdomains_unlock ();
899 mono_jit_info_find_aot_module (guint8* addr)
901 guint left = 0, right;
906 mono_appdomains_lock ();
908 right = aot_modules->len;
909 while (left < right) {
910 guint pos = (left + right) / 2;
911 AotModuleInfo *ai = g_array_index (aot_modules, gpointer, pos);
913 if (addr < (guint8*)ai->start)
915 else if (addr >= (guint8*)ai->end)
918 mono_appdomains_unlock ();
923 mono_appdomains_unlock ();
929 mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func)
931 jit_info_find_in_aot_func = func;
935 mono_jit_info_get_code_start (MonoJitInfo* ji)
937 return ji->code_start;
941 mono_jit_info_get_code_size (MonoJitInfo* ji)
943 return ji->code_size;
947 mono_jit_info_get_method (MonoJitInfo* ji)
953 jit_info_key_extract (gpointer value)
955 MonoJitInfo *info = (MonoJitInfo*)value;
961 jit_info_next_value (gpointer value)
963 MonoJitInfo *info = (MonoJitInfo*)value;
965 return (gpointer*)&info->next_jit_code_hash;
969 mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
971 mono_internal_hash_table_init (jit_code_hash,
972 mono_aligned_addr_hash,
973 jit_info_key_extract,
974 jit_info_next_value);
978 mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
980 if (ji->has_generic_jit_info)
981 return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
987 * mono_jit_info_get_generic_sharing_context:
990 * Returns the jit info's generic sharing context, or NULL if it
993 MonoGenericSharingContext*
994 mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
996 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
999 return gi->generic_sharing_context;
1005 * mono_jit_info_set_generic_sharing_context:
1007 * @gsctx: a generic sharing context
1009 * Sets the jit info's generic sharing context. The jit info must
1010 * have memory allocated for the context.
1013 mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
1015 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
1019 gi->generic_sharing_context = gsctx;
1022 MonoTryBlockHoleTableJitInfo*
1023 mono_jit_info_get_try_block_hole_table_info (MonoJitInfo *ji)
1025 if (ji->has_try_block_holes) {
1026 char *ptr = (char*)&ji->clauses [ji->num_clauses];
1027 if (ji->has_generic_jit_info)
1028 ptr += sizeof (MonoGenericJitInfo);
1029 return (MonoTryBlockHoleTableJitInfo*)ptr;
1035 mono_install_create_domain_hook (MonoCreateDomainFunc func)
1037 create_domain_hook = func;
1041 mono_install_free_domain_hook (MonoFreeDomainFunc func)
1043 free_domain_hook = func;
1047 * mono_string_equal:
1048 * @s1: First string to compare
1049 * @s2: Second string to compare
1051 * Returns FALSE if the strings differ.
1054 mono_string_equal (MonoString *s1, MonoString *s2)
1056 int l1 = mono_string_length (s1);
1057 int l2 = mono_string_length (s2);
1064 return memcmp (mono_string_chars (s1), mono_string_chars (s2), l1 * 2) == 0;
1069 * @s: the string to hash
1071 * Returns the hash for the string.
1074 mono_string_hash (MonoString *s)
1076 const guint16 *p = mono_string_chars (s);
1077 int i, len = mono_string_length (s);
1080 for (i = 0; i < len; i++) {
1081 h = (h << 5) - h + *p;
1089 mono_ptrarray_equal (gpointer *s1, gpointer *s2)
1091 int len = GPOINTER_TO_INT (s1 [0]);
1092 if (len != GPOINTER_TO_INT (s2 [0]))
1095 return memcmp (s1 + 1, s2 + 1, len * sizeof(gpointer)) == 0;
1099 mono_ptrarray_hash (gpointer *s)
1102 int len = GPOINTER_TO_INT (s [0]);
1105 for (i = 1; i < len; i++)
1106 hash += GPOINTER_TO_UINT (s [i]);
1112 * Allocate an id for domain and set domain->domain_id.
1113 * LOCKING: must be called while holding appdomains_mutex.
1114 * We try to assign low numbers to the domain, so it can be used
1115 * as an index in data tables to lookup domain-specific info
1116 * with minimal memory overhead. We also try not to reuse the
1117 * same id too quickly (to help debugging).
1120 domain_id_alloc (MonoDomain *domain)
1123 if (!appdomains_list) {
1124 appdomain_list_size = 2;
1125 appdomains_list = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1127 for (i = appdomain_next; i < appdomain_list_size; ++i) {
1128 if (!appdomains_list [i]) {
1134 for (i = 0; i < appdomain_next; ++i) {
1135 if (!appdomains_list [i]) {
1142 MonoDomain **new_list;
1143 int new_size = appdomain_list_size * 2;
1144 if (new_size >= (1 << 16))
1145 g_assert_not_reached ();
1146 id = appdomain_list_size;
1147 new_list = mono_gc_alloc_fixed (new_size * sizeof (void*), NULL);
1148 memcpy (new_list, appdomains_list, appdomain_list_size * sizeof (void*));
1149 mono_gc_free_fixed (appdomains_list);
1150 appdomains_list = new_list;
1151 appdomain_list_size = new_size;
1153 domain->domain_id = id;
1154 appdomains_list [id] = domain;
1156 if (appdomain_next > appdomain_list_size)
1161 static gsize domain_gc_bitmap [sizeof(MonoDomain)/4/32 + 1];
1162 static gpointer domain_gc_desc = NULL;
1163 static guint32 domain_shadow_serial = 0L;
1166 mono_domain_create (void)
1169 guint32 shadow_serial;
1171 mono_appdomains_lock ();
1172 shadow_serial = domain_shadow_serial++;
1174 if (!domain_gc_desc) {
1175 unsigned int i, bit = 0;
1176 for (i = G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_OBJECT); i < G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_GC_TRACKED); i += sizeof (gpointer)) {
1177 bit = i / sizeof (gpointer);
1178 domain_gc_bitmap [bit / 32] |= (gsize) 1 << (bit % 32);
1180 domain_gc_desc = mono_gc_make_descr_from_bitmap ((gsize*)domain_gc_bitmap, bit + 1);
1182 mono_appdomains_unlock ();
1184 #ifdef HAVE_BOEHM_GC
1186 * Boehm doesn't like roots inside GC allocated objects, and alloc_fixed returns
1187 * a GC_MALLOC-ed object, contrary to the api docs. This causes random crashes when
1188 * running the corlib test suite.
1189 * To solve this, we pass a NULL descriptor, and don't register roots.
1191 domain = mono_gc_alloc_fixed (sizeof (MonoDomain), NULL);
1193 domain = mono_gc_alloc_fixed (sizeof (MonoDomain), domain_gc_desc);
1194 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);
1196 domain->shadow_serial = shadow_serial;
1197 domain->domain = NULL;
1198 domain->setup = NULL;
1199 domain->friendly_name = NULL;
1200 domain->search_path = NULL;
1202 mono_profiler_appdomain_event (domain, MONO_PROFILE_START_LOAD);
1204 domain->mp = mono_mempool_new ();
1205 domain->code_mp = mono_code_manager_new ();
1206 domain->env = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1207 domain->domain_assemblies = NULL;
1208 domain->assembly_bindings = NULL;
1209 domain->assembly_bindings_parsed = FALSE;
1210 domain->class_vtable_array = g_ptr_array_new ();
1211 domain->proxy_vtable_hash = g_hash_table_new ((GHashFunc)mono_ptrarray_hash, (GCompareFunc)mono_ptrarray_equal);
1212 domain->static_data_array = NULL;
1213 mono_jit_code_hash_init (&domain->jit_code_hash);
1214 domain->ldstr_table = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1215 domain->num_jit_info_tables = 1;
1216 domain->jit_info_table = jit_info_table_new (domain);
1217 domain->jit_info_free_queue = NULL;
1218 domain->finalizable_objects_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1219 #ifndef HAVE_SGEN_GC
1220 domain->track_resurrection_handles_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1223 InitializeCriticalSection (&domain->lock);
1224 InitializeCriticalSection (&domain->assemblies_lock);
1225 InitializeCriticalSection (&domain->jit_code_hash_lock);
1226 InitializeCriticalSection (&domain->finalizable_objects_hash_lock);
1228 domain->method_rgctx_hash = NULL;
1230 mono_appdomains_lock ();
1231 domain_id_alloc (domain);
1232 mono_appdomains_unlock ();
1234 mono_perfcounters->loader_appdomains++;
1235 mono_perfcounters->loader_total_appdomains++;
1237 mono_debug_domain_create (domain);
1239 if (create_domain_hook)
1240 create_domain_hook (domain);
1242 mono_profiler_appdomain_loaded (domain, MONO_PROFILE_OK);
1248 * mono_init_internal:
1250 * Creates the initial application domain and initializes the mono_defaults
1252 * This function is guaranteed to not run any IL code.
1253 * If exe_filename is not NULL, the method will determine the required runtime
1254 * from the exe configuration file or the version PE field.
1255 * If runtime_version is not NULL, that runtime version will be used.
1256 * Either exe_filename or runtime_version must be provided.
1258 * Returns: the initial domain.
1261 mono_init_internal (const char *filename, const char *exe_filename, const char *runtime_version)
1263 static MonoDomain *domain = NULL;
1264 MonoAssembly *ass = NULL;
1265 MonoImageOpenStatus status = MONO_IMAGE_OK;
1266 const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
1270 g_assert_not_reached ();
1273 /* Avoid system error message boxes. */
1274 SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1276 mono_load_coree (exe_filename);
1279 mono_perfcounters_init ();
1281 mono_counters_register ("Max native code in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_size);
1282 mono_counters_register ("Max code space allocated in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_alloc);
1283 mono_counters_register ("Total code space allocated", MONO_COUNTER_INT|MONO_COUNTER_JIT, &total_domain_code_alloc);
1285 mono_gc_base_init ();
1287 appdomain_thread_id = TlsAlloc ();
1289 InitializeCriticalSection (&appdomains_mutex);
1291 mono_metadata_init ();
1292 mono_images_init ();
1293 mono_assemblies_init ();
1294 mono_classes_init ();
1295 mono_loader_init ();
1296 mono_reflection_init ();
1298 /* FIXME: When should we release this memory? */
1299 MONO_GC_REGISTER_ROOT (appdomains_list);
1301 domain = mono_domain_create ();
1302 mono_root_domain = domain;
1304 SET_APPDOMAIN (domain);
1306 /* Get a list of runtimes supported by the exe */
1307 if (exe_filename != NULL) {
1309 * This function will load the exe file as a MonoImage. We need to close it, but
1310 * that would mean it would be reloaded later. So instead, we save it to
1311 * exe_image, and close it during shutdown.
1313 get_runtimes_from_exe (exe_filename, &exe_image, runtimes);
1316 exe_image = mono_assembly_open_from_bundle (exe_filename, NULL, FALSE);
1318 exe_image = mono_image_open (exe_filename, NULL);
1320 mono_fixup_exe_image (exe_image);
1322 } else if (runtime_version != NULL) {
1323 runtimes [0] = get_runtime_by_version (runtime_version);
1324 runtimes [1] = NULL;
1327 if (runtimes [0] == NULL) {
1328 const MonoRuntimeInfo *default_runtime = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
1329 runtimes [0] = default_runtime;
1330 runtimes [1] = NULL;
1331 g_print ("WARNING: The runtime version supported by this application is unavailable.\n");
1332 g_print ("Using default runtime: %s\n", default_runtime->runtime_version);
1335 /* The selected runtime will be the first one for which there is a mscrolib.dll */
1336 for (n = 0; runtimes [n] != NULL && ass == NULL; n++) {
1337 current_runtime = runtimes [n];
1338 ass = mono_assembly_load_corlib (current_runtime, &status);
1339 if (status != MONO_IMAGE_OK && status != MONO_IMAGE_ERROR_ERRNO)
1344 if ((status != MONO_IMAGE_OK) || (ass == NULL)) {
1346 case MONO_IMAGE_ERROR_ERRNO: {
1347 char *corlib_file = g_build_filename (mono_assembly_getrootdir (), "mono", current_runtime->framework_version, "mscorlib.dll", NULL);
1348 g_print ("The assembly mscorlib.dll was not found or could not be loaded.\n");
1349 g_print ("It should have been installed in the `%s' directory.\n", corlib_file);
1350 g_free (corlib_file);
1353 case MONO_IMAGE_IMAGE_INVALID:
1354 g_print ("The file %s/mscorlib.dll is an invalid CIL image\n",
1355 mono_assembly_getrootdir ());
1357 case MONO_IMAGE_MISSING_ASSEMBLYREF:
1358 g_print ("Missing assembly reference in %s/mscorlib.dll\n",
1359 mono_assembly_getrootdir ());
1362 /* to suppress compiler warning */
1368 mono_defaults.corlib = mono_assembly_get_image (ass);
1370 mono_defaults.object_class = mono_class_from_name (
1371 mono_defaults.corlib, "System", "Object");
1372 g_assert (mono_defaults.object_class != 0);
1374 mono_defaults.void_class = mono_class_from_name (
1375 mono_defaults.corlib, "System", "Void");
1376 g_assert (mono_defaults.void_class != 0);
1378 mono_defaults.boolean_class = mono_class_from_name (
1379 mono_defaults.corlib, "System", "Boolean");
1380 g_assert (mono_defaults.boolean_class != 0);
1382 mono_defaults.byte_class = mono_class_from_name (
1383 mono_defaults.corlib, "System", "Byte");
1384 g_assert (mono_defaults.byte_class != 0);
1386 mono_defaults.sbyte_class = mono_class_from_name (
1387 mono_defaults.corlib, "System", "SByte");
1388 g_assert (mono_defaults.sbyte_class != 0);
1390 mono_defaults.int16_class = mono_class_from_name (
1391 mono_defaults.corlib, "System", "Int16");
1392 g_assert (mono_defaults.int16_class != 0);
1394 mono_defaults.uint16_class = mono_class_from_name (
1395 mono_defaults.corlib, "System", "UInt16");
1396 g_assert (mono_defaults.uint16_class != 0);
1398 mono_defaults.int32_class = mono_class_from_name (
1399 mono_defaults.corlib, "System", "Int32");
1400 g_assert (mono_defaults.int32_class != 0);
1402 mono_defaults.uint32_class = mono_class_from_name (
1403 mono_defaults.corlib, "System", "UInt32");
1404 g_assert (mono_defaults.uint32_class != 0);
1406 mono_defaults.uint_class = mono_class_from_name (
1407 mono_defaults.corlib, "System", "UIntPtr");
1408 g_assert (mono_defaults.uint_class != 0);
1410 mono_defaults.int_class = mono_class_from_name (
1411 mono_defaults.corlib, "System", "IntPtr");
1412 g_assert (mono_defaults.int_class != 0);
1414 mono_defaults.int64_class = mono_class_from_name (
1415 mono_defaults.corlib, "System", "Int64");
1416 g_assert (mono_defaults.int64_class != 0);
1418 mono_defaults.uint64_class = mono_class_from_name (
1419 mono_defaults.corlib, "System", "UInt64");
1420 g_assert (mono_defaults.uint64_class != 0);
1422 mono_defaults.single_class = mono_class_from_name (
1423 mono_defaults.corlib, "System", "Single");
1424 g_assert (mono_defaults.single_class != 0);
1426 mono_defaults.double_class = mono_class_from_name (
1427 mono_defaults.corlib, "System", "Double");
1428 g_assert (mono_defaults.double_class != 0);
1430 mono_defaults.char_class = mono_class_from_name (
1431 mono_defaults.corlib, "System", "Char");
1432 g_assert (mono_defaults.char_class != 0);
1434 mono_defaults.string_class = mono_class_from_name (
1435 mono_defaults.corlib, "System", "String");
1436 g_assert (mono_defaults.string_class != 0);
1438 mono_defaults.enum_class = mono_class_from_name (
1439 mono_defaults.corlib, "System", "Enum");
1440 g_assert (mono_defaults.enum_class != 0);
1442 mono_defaults.array_class = mono_class_from_name (
1443 mono_defaults.corlib, "System", "Array");
1444 g_assert (mono_defaults.array_class != 0);
1446 mono_defaults.delegate_class = mono_class_from_name (
1447 mono_defaults.corlib, "System", "Delegate");
1448 g_assert (mono_defaults.delegate_class != 0 );
1450 mono_defaults.multicastdelegate_class = mono_class_from_name (
1451 mono_defaults.corlib, "System", "MulticastDelegate");
1452 g_assert (mono_defaults.multicastdelegate_class != 0 );
1454 mono_defaults.asyncresult_class = mono_class_from_name (
1455 mono_defaults.corlib, "System.Runtime.Remoting.Messaging",
1457 g_assert (mono_defaults.asyncresult_class != 0 );
1459 mono_defaults.manualresetevent_class = mono_class_from_name (
1460 mono_defaults.corlib, "System.Threading", "ManualResetEvent");
1461 g_assert (mono_defaults.manualresetevent_class != 0 );
1463 mono_defaults.typehandle_class = mono_class_from_name (
1464 mono_defaults.corlib, "System", "RuntimeTypeHandle");
1465 g_assert (mono_defaults.typehandle_class != 0);
1467 mono_defaults.methodhandle_class = mono_class_from_name (
1468 mono_defaults.corlib, "System", "RuntimeMethodHandle");
1469 g_assert (mono_defaults.methodhandle_class != 0);
1471 mono_defaults.fieldhandle_class = mono_class_from_name (
1472 mono_defaults.corlib, "System", "RuntimeFieldHandle");
1473 g_assert (mono_defaults.fieldhandle_class != 0);
1475 mono_defaults.systemtype_class = mono_class_from_name (
1476 mono_defaults.corlib, "System", "Type");
1477 g_assert (mono_defaults.systemtype_class != 0);
1479 mono_defaults.monotype_class = mono_class_from_name (
1480 mono_defaults.corlib, "System", "MonoType");
1481 g_assert (mono_defaults.monotype_class != 0);
1483 mono_defaults.exception_class = mono_class_from_name (
1484 mono_defaults.corlib, "System", "Exception");
1485 g_assert (mono_defaults.exception_class != 0);
1487 mono_defaults.threadabortexception_class = mono_class_from_name (
1488 mono_defaults.corlib, "System.Threading", "ThreadAbortException");
1489 g_assert (mono_defaults.threadabortexception_class != 0);
1491 mono_defaults.thread_class = mono_class_from_name (
1492 mono_defaults.corlib, "System.Threading", "Thread");
1493 g_assert (mono_defaults.thread_class != 0);
1495 mono_defaults.internal_thread_class = mono_class_from_name (
1496 mono_defaults.corlib, "System.Threading", "InternalThread");
1497 if (!mono_defaults.internal_thread_class) {
1498 /* This can happen with an old mscorlib */
1499 fprintf (stderr, "Corlib too old for this runtime.\n");
1500 fprintf (stderr, "Loaded from: %s\n",
1501 mono_defaults.corlib? mono_image_get_filename (mono_defaults.corlib): "unknown");
1505 mono_defaults.appdomain_class = mono_class_from_name (
1506 mono_defaults.corlib, "System", "AppDomain");
1507 g_assert (mono_defaults.appdomain_class != 0);
1509 mono_defaults.transparent_proxy_class = mono_class_from_name (
1510 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "TransparentProxy");
1511 g_assert (mono_defaults.transparent_proxy_class != 0);
1513 mono_defaults.real_proxy_class = mono_class_from_name (
1514 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "RealProxy");
1515 g_assert (mono_defaults.real_proxy_class != 0);
1517 mono_defaults.mono_method_message_class = mono_class_from_name (
1518 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", "MonoMethodMessage");
1519 g_assert (mono_defaults.mono_method_message_class != 0);
1521 mono_defaults.field_info_class = mono_class_from_name (
1522 mono_defaults.corlib, "System.Reflection", "FieldInfo");
1523 g_assert (mono_defaults.field_info_class != 0);
1525 mono_defaults.method_info_class = mono_class_from_name (
1526 mono_defaults.corlib, "System.Reflection", "MethodInfo");
1527 g_assert (mono_defaults.method_info_class != 0);
1529 mono_defaults.stringbuilder_class = mono_class_from_name (
1530 mono_defaults.corlib, "System.Text", "StringBuilder");
1531 g_assert (mono_defaults.stringbuilder_class != 0);
1533 mono_defaults.math_class = mono_class_from_name (
1534 mono_defaults.corlib, "System", "Math");
1535 g_assert (mono_defaults.math_class != 0);
1537 mono_defaults.stack_frame_class = mono_class_from_name (
1538 mono_defaults.corlib, "System.Diagnostics", "StackFrame");
1539 g_assert (mono_defaults.stack_frame_class != 0);
1541 mono_defaults.stack_trace_class = mono_class_from_name (
1542 mono_defaults.corlib, "System.Diagnostics", "StackTrace");
1543 g_assert (mono_defaults.stack_trace_class != 0);
1545 mono_defaults.marshal_class = mono_class_from_name (
1546 mono_defaults.corlib, "System.Runtime.InteropServices", "Marshal");
1547 g_assert (mono_defaults.marshal_class != 0);
1549 mono_defaults.iserializeable_class = mono_class_from_name (
1550 mono_defaults.corlib, "System.Runtime.Serialization", "ISerializable");
1551 g_assert (mono_defaults.iserializeable_class != 0);
1553 mono_defaults.serializationinfo_class = mono_class_from_name (
1554 mono_defaults.corlib, "System.Runtime.Serialization", "SerializationInfo");
1555 g_assert (mono_defaults.serializationinfo_class != 0);
1557 mono_defaults.streamingcontext_class = mono_class_from_name (
1558 mono_defaults.corlib, "System.Runtime.Serialization", "StreamingContext");
1559 g_assert (mono_defaults.streamingcontext_class != 0);
1561 mono_defaults.typed_reference_class = mono_class_from_name (
1562 mono_defaults.corlib, "System", "TypedReference");
1563 g_assert (mono_defaults.typed_reference_class != 0);
1565 mono_defaults.argumenthandle_class = mono_class_from_name (
1566 mono_defaults.corlib, "System", "RuntimeArgumentHandle");
1567 g_assert (mono_defaults.argumenthandle_class != 0);
1569 mono_defaults.marshalbyrefobject_class = mono_class_from_name (
1570 mono_defaults.corlib, "System", "MarshalByRefObject");
1571 g_assert (mono_defaults.marshalbyrefobject_class != 0);
1573 mono_defaults.monitor_class = mono_class_from_name (
1574 mono_defaults.corlib, "System.Threading", "Monitor");
1575 g_assert (mono_defaults.monitor_class != 0);
1577 mono_defaults.iremotingtypeinfo_class = mono_class_from_name (
1578 mono_defaults.corlib, "System.Runtime.Remoting", "IRemotingTypeInfo");
1579 g_assert (mono_defaults.iremotingtypeinfo_class != 0);
1581 mono_defaults.runtimesecurityframe_class = mono_class_from_name (
1582 mono_defaults.corlib, "System.Security", "RuntimeSecurityFrame");
1584 mono_defaults.executioncontext_class = mono_class_from_name (
1585 mono_defaults.corlib, "System.Threading", "ExecutionContext");
1587 mono_defaults.internals_visible_class = mono_class_from_name (
1588 mono_defaults.corlib, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute");
1590 mono_defaults.critical_finalizer_object = mono_class_from_name (
1591 mono_defaults.corlib, "System.Runtime.ConstrainedExecution", "CriticalFinalizerObject");
1594 * mscorlib needs a little help, only now it can load its friends list (after we have
1595 * loaded the InternalsVisibleToAttribute), load it now
1597 mono_assembly_load_friends (ass);
1599 mono_defaults.safehandle_class = mono_class_from_name (
1600 mono_defaults.corlib, "System.Runtime.InteropServices", "SafeHandle");
1602 mono_defaults.handleref_class = mono_class_from_name (
1603 mono_defaults.corlib, "System.Runtime.InteropServices", "HandleRef");
1605 mono_defaults.attribute_class = mono_class_from_name (
1606 mono_defaults.corlib, "System", "Attribute");
1608 mono_defaults.customattribute_data_class = mono_class_from_name (
1609 mono_defaults.corlib, "System.Reflection", "CustomAttributeData");
1611 /* these are initialized lazily when COM features are used */
1612 mono_defaults.variant_class = NULL;
1613 mono_defaults.com_object_class = NULL;
1614 mono_defaults.com_interop_proxy_class = NULL;
1615 mono_defaults.iunknown_class = NULL;
1616 mono_defaults.idispatch_class = NULL;
1619 * Note that mono_defaults.generic_*_class is only non-NULL if we're
1620 * using the 2.0 corlib.
1622 mono_class_init (mono_defaults.array_class);
1623 mono_defaults.generic_nullable_class = mono_class_from_name (
1624 mono_defaults.corlib, "System", "Nullable`1");
1625 mono_defaults.generic_ilist_class = mono_class_from_name (
1626 mono_defaults.corlib, "System.Collections.Generic", "IList`1");
1628 domain->friendly_name = g_path_get_basename (filename);
1630 _mono_debug_init_corlib (domain);
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 default runtime version.
1643 * Returns: the initial domain.
1646 mono_init (const char *domain_name)
1648 return mono_init_internal (domain_name, NULL, DEFAULT_RUNTIME_VERSION);
1652 * mono_init_from_assembly:
1653 * @domain_name: name to give to the initial domain
1654 * @filename: filename to load on startup
1656 * Used by the runtime, users should use mono_jit_init instead.
1658 * Creates the initial application domain and initializes the mono_defaults
1660 * This function is guaranteed to not run any IL code.
1661 * The runtime is initialized using the runtime version required by the
1662 * provided executable. The version is determined by looking at the exe
1663 * configuration file and the version PE field)
1665 * Returns: the initial domain.
1668 mono_init_from_assembly (const char *domain_name, const char *filename)
1670 return mono_init_internal (domain_name, filename, NULL);
1674 * mono_init_version:
1676 * Used by the runtime, users should use mono_jit_init instead.
1678 * Creates the initial application domain and initializes the mono_defaults
1681 * This function is guaranteed to not run any IL code.
1682 * The runtime is initialized using the provided rutime version.
1684 * Returns: the initial domain.
1687 mono_init_version (const char *domain_name, const char *version)
1689 return mono_init_internal (domain_name, NULL, version);
1693 * mono_init_com_types:
1695 * Initializes all types needed for COM Interop in mono_defaults structure.
1698 mono_init_com_types (void)
1700 static gboolean initialized = FALSE;
1705 /* FIXME: do I need some threading protection here */
1707 g_assert (mono_defaults.corlib);
1709 mono_defaults.variant_class = mono_class_from_name (
1710 mono_defaults.corlib, "System", "Variant");
1711 g_assert (mono_defaults.variant_class != 0);
1713 mono_defaults.com_object_class = mono_class_from_name (
1714 mono_defaults.corlib, "System", "__ComObject");
1715 g_assert (mono_defaults.com_object_class != 0);
1717 mono_defaults.com_interop_proxy_class = mono_class_from_name (
1718 mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
1719 g_assert (mono_defaults.com_interop_proxy_class != 0);
1721 mono_defaults.iunknown_class = mono_class_from_name (
1722 mono_defaults.corlib, "Mono.Interop", "IUnknown");
1723 g_assert (mono_defaults.iunknown_class != 0);
1725 mono_defaults.idispatch_class = mono_class_from_name (
1726 mono_defaults.corlib, "Mono.Interop", "IDispatch");
1727 g_assert (mono_defaults.idispatch_class != 0);
1735 * Cleans up all metadata modules.
1740 mono_close_exe_image ();
1742 mono_defaults.corlib = NULL;
1744 mono_config_cleanup ();
1745 mono_loader_cleanup ();
1746 mono_classes_cleanup ();
1747 mono_assemblies_cleanup ();
1748 mono_images_cleanup ();
1749 mono_debug_cleanup ();
1750 mono_metadata_cleanup ();
1752 TlsFree (appdomain_thread_id);
1753 DeleteCriticalSection (&appdomains_mutex);
1756 * This should be called last as TlsGetValue ()/TlsSetValue () can be called during
1765 mono_close_exe_image (void)
1768 mono_image_close (exe_image);
1772 * mono_get_root_domain:
1774 * The root AppDomain is the initial domain created by the runtime when it is
1775 * initialized. Programs execute on this AppDomain, but can create new ones
1776 * later. Currently there is no unmanaged API to create new AppDomains, this
1777 * must be done from managed code.
1779 * Returns: the root appdomain, to obtain the current domain, use mono_domain_get ()
1782 mono_get_root_domain (void)
1784 return mono_root_domain;
1790 * Returns: the current domain, to obtain the root domain use
1791 * mono_get_root_domain().
1796 return GET_APPDOMAIN ();
1800 mono_domain_unset (void)
1802 SET_APPDOMAIN (NULL);
1806 mono_domain_set_internal_with_options (MonoDomain *domain, gboolean migrate_exception)
1808 MonoInternalThread *thread;
1810 if (mono_domain_get () == domain)
1813 SET_APPDOMAIN (domain);
1814 SET_APPCONTEXT (domain->default_context);
1816 if (migrate_exception) {
1817 thread = mono_thread_internal_current ();
1818 if (!thread->abort_exc)
1821 g_assert (thread->abort_exc->object.vtable->domain != domain);
1822 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
1823 g_assert (thread->abort_exc->object.vtable->domain == domain);
1828 * mono_domain_set_internal:
1829 * @domain: the new domain
1831 * Sets the current domain to @domain.
1834 mono_domain_set_internal (MonoDomain *domain)
1836 mono_domain_set_internal_with_options (domain, TRUE);
1840 mono_domain_foreach (MonoDomainFunc func, gpointer user_data)
1846 * Create a copy of the data to avoid calling the user callback
1847 * inside the lock because that could lead to deadlocks.
1848 * We can do this because this function is not perf. critical.
1850 mono_appdomains_lock ();
1851 size = appdomain_list_size;
1852 copy = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1853 memcpy (copy, appdomains_list, appdomain_list_size * sizeof (void*));
1854 mono_appdomains_unlock ();
1856 for (i = 0; i < size; ++i) {
1858 func (copy [i], user_data);
1861 mono_gc_free_fixed (copy);
1865 * mono_domain_assembly_open:
1866 * @domain: the application domain
1867 * @name: file name of the assembly
1869 * fixme: maybe we should integrate this with mono_assembly_open ??
1872 mono_domain_assembly_open (MonoDomain *domain, const char *name)
1874 MonoDomain *current;
1878 mono_domain_assemblies_lock (domain);
1879 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1881 if (strcmp (name, ass->aname.name) == 0) {
1882 mono_domain_assemblies_unlock (domain);
1886 mono_domain_assemblies_unlock (domain);
1888 if (domain != mono_domain_get ()) {
1889 current = mono_domain_get ();
1891 mono_domain_set (domain, FALSE);
1892 ass = mono_assembly_open (name, NULL);
1893 mono_domain_set (current, FALSE);
1895 ass = mono_assembly_open (name, NULL);
1901 #ifndef HAVE_SGEN_GC
1903 free_slist (gpointer key, gpointer value, gpointer user_data)
1905 g_slist_free (value);
1911 unregister_vtable_reflection_type (MonoVTable *vtable)
1913 MonoObject *type = vtable->type;
1915 if (type->vtable->klass != mono_defaults.monotype_class)
1916 mono_gc_deregister_root ((char*)&vtable->type);
1921 mono_domain_free (MonoDomain *domain, gboolean force)
1923 int code_size, code_alloc;
1925 if ((domain == mono_root_domain) && !force) {
1926 g_warning ("cant unload root domain");
1930 if (mono_dont_free_domains)
1933 mono_profiler_appdomain_event (domain, MONO_PROFILE_START_UNLOAD);
1935 mono_debug_domain_unload (domain);
1937 mono_appdomains_lock ();
1938 appdomains_list [domain->domain_id] = NULL;
1939 mono_appdomains_unlock ();
1941 /* must do this early as it accesses fields and types */
1942 if (domain->special_static_fields) {
1943 mono_alloc_special_static_data_free (domain->special_static_fields);
1944 g_hash_table_destroy (domain->special_static_fields);
1945 domain->special_static_fields = NULL;
1949 * We must destroy all these hash tables here because they
1950 * contain references to managed objects belonging to the
1951 * domain. Once we let the GC clear the domain there must be
1952 * no more such references, or we'll crash if a collection
1955 mono_g_hash_table_destroy (domain->ldstr_table);
1956 domain->ldstr_table = NULL;
1958 mono_g_hash_table_destroy (domain->env);
1961 mono_reflection_cleanup_domain (domain);
1963 if (domain->type_hash) {
1964 mono_g_hash_table_destroy (domain->type_hash);
1965 domain->type_hash = NULL;
1967 if (domain->type_init_exception_hash) {
1968 mono_g_hash_table_destroy (domain->type_init_exception_hash);
1969 domain->type_init_exception_hash = NULL;
1972 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1973 MonoAssembly *ass = tmp->data;
1974 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);
1975 if (!mono_assembly_close_except_image_pools (ass))
1980 if (domain->class_vtable_array) {
1982 for (i = 0; i < domain->class_vtable_array->len; ++i)
1983 unregister_vtable_reflection_type (g_ptr_array_index (domain->class_vtable_array, i));
1987 mono_gc_clear_domain (domain);
1989 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1990 MonoAssembly *ass = tmp->data;
1992 mono_assembly_close_finish (ass);
1994 g_slist_free (domain->domain_assemblies);
1995 domain->domain_assemblies = NULL;
1998 * Send this after the assemblies have been unloaded and the domain is still in a
2001 mono_profiler_appdomain_event (domain, MONO_PROFILE_END_UNLOAD);
2003 if (free_domain_hook)
2004 free_domain_hook (domain);
2006 /* FIXME: free delegate_hash_table when it's used */
2007 if (domain->search_path) {
2008 g_strfreev (domain->search_path);
2009 domain->search_path = NULL;
2011 domain->create_proxy_for_type_method = NULL;
2012 domain->private_invoke_method = NULL;
2013 domain->default_context = NULL;
2014 domain->out_of_memory_ex = NULL;
2015 domain->null_reference_ex = NULL;
2016 domain->stack_overflow_ex = NULL;
2017 domain->ephemeron_tombstone = NULL;
2018 domain->entry_assembly = NULL;
2020 g_free (domain->friendly_name);
2021 domain->friendly_name = NULL;
2022 g_ptr_array_free (domain->class_vtable_array, TRUE);
2023 domain->class_vtable_array = NULL;
2024 g_hash_table_destroy (domain->proxy_vtable_hash);
2025 domain->proxy_vtable_hash = NULL;
2026 if (domain->static_data_array) {
2027 mono_gc_free_fixed (domain->static_data_array);
2028 domain->static_data_array = NULL;
2030 mono_internal_hash_table_destroy (&domain->jit_code_hash);
2033 * There might still be jit info tables of this domain which
2034 * are not freed. Since the domain cannot be in use anymore,
2035 * this will free them.
2037 mono_thread_hazardous_try_free_all ();
2038 g_assert (domain->num_jit_info_tables == 1);
2039 jit_info_table_free (domain->jit_info_table);
2040 domain->jit_info_table = NULL;
2041 g_assert (!domain->jit_info_free_queue);
2043 /* collect statistics */
2044 code_alloc = mono_code_manager_size (domain->code_mp, &code_size);
2045 total_domain_code_alloc += code_alloc;
2046 max_domain_code_alloc = MAX (max_domain_code_alloc, code_alloc);
2047 max_domain_code_size = MAX (max_domain_code_size, code_size);
2049 #ifdef DEBUG_DOMAIN_UNLOAD
2050 mono_mempool_invalidate (domain->mp);
2051 mono_code_manager_invalidate (domain->code_mp);
2053 mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (domain->mp);
2054 mono_mempool_destroy (domain->mp);
2056 mono_code_manager_destroy (domain->code_mp);
2057 domain->code_mp = NULL;
2060 g_hash_table_destroy (domain->finalizable_objects_hash);
2061 domain->finalizable_objects_hash = NULL;
2062 #ifndef HAVE_SGEN_GC
2063 if (domain->track_resurrection_objects_hash) {
2064 g_hash_table_foreach (domain->track_resurrection_objects_hash, free_slist, NULL);
2065 g_hash_table_destroy (domain->track_resurrection_objects_hash);
2067 if (domain->track_resurrection_handles_hash)
2068 g_hash_table_destroy (domain->track_resurrection_handles_hash);
2070 if (domain->method_rgctx_hash) {
2071 g_hash_table_destroy (domain->method_rgctx_hash);
2072 domain->method_rgctx_hash = NULL;
2074 if (domain->generic_virtual_cases) {
2075 g_hash_table_destroy (domain->generic_virtual_cases);
2076 domain->generic_virtual_cases = NULL;
2079 DeleteCriticalSection (&domain->finalizable_objects_hash_lock);
2080 DeleteCriticalSection (&domain->assemblies_lock);
2081 DeleteCriticalSection (&domain->jit_code_hash_lock);
2082 DeleteCriticalSection (&domain->lock);
2083 domain->setup = NULL;
2085 mono_gc_deregister_root ((char*)&(domain->MONO_DOMAIN_FIRST_GC_TRACKED));
2087 /* FIXME: anything else required ? */
2089 mono_gc_free_fixed (domain);
2091 mono_perfcounters->loader_appdomains--;
2093 if ((domain == mono_root_domain))
2094 mono_root_domain = NULL;
2098 * mono_domain_get_id:
2101 * Returns: the a domain for a specific domain id.
2104 mono_domain_get_by_id (gint32 domainid)
2106 MonoDomain * domain;
2108 mono_appdomains_lock ();
2109 if (domainid < appdomain_list_size)
2110 domain = appdomains_list [domainid];
2113 mono_appdomains_unlock ();
2119 mono_domain_get_id (MonoDomain *domain)
2121 return domain->domain_id;
2125 * mono_domain_alloc:
2127 * LOCKING: Acquires the domain lock.
2130 mono_domain_alloc (MonoDomain *domain, guint size)
2134 mono_domain_lock (domain);
2135 mono_perfcounters->loader_bytes += size;
2136 res = mono_mempool_alloc (domain->mp, size);
2137 mono_domain_unlock (domain);
2143 * mono_domain_alloc0:
2145 * LOCKING: Acquires the domain lock.
2148 mono_domain_alloc0 (MonoDomain *domain, guint size)
2152 mono_domain_lock (domain);
2153 mono_perfcounters->loader_bytes += size;
2154 res = mono_mempool_alloc0 (domain->mp, size);
2155 mono_domain_unlock (domain);
2161 * mono_domain_code_reserve:
2163 * LOCKING: Acquires the domain lock.
2166 mono_domain_code_reserve (MonoDomain *domain, int size)
2170 mono_domain_lock (domain);
2171 res = mono_code_manager_reserve (domain->code_mp, size);
2172 mono_domain_unlock (domain);
2178 * mono_domain_code_reserve_align:
2180 * LOCKING: Acquires the domain lock.
2183 mono_domain_code_reserve_align (MonoDomain *domain, int size, int alignment)
2187 mono_domain_lock (domain);
2188 res = mono_code_manager_reserve_align (domain->code_mp, size, alignment);
2189 mono_domain_unlock (domain);
2195 * mono_domain_code_commit:
2197 * LOCKING: Acquires the domain lock.
2200 mono_domain_code_commit (MonoDomain *domain, void *data, int size, int newsize)
2202 mono_domain_lock (domain);
2203 mono_code_manager_commit (domain->code_mp, data, size, newsize);
2204 mono_domain_unlock (domain);
2208 * mono_domain_code_foreach:
2209 * Iterate over the code thunks of the code manager of @domain.
2211 * The @func callback MUST not take any locks. If it really needs to, it must respect
2212 * the locking rules of the runtime: http://www.mono-project.com/Mono:Runtime:Documentation:ThreadSafety
2213 * LOCKING: Acquires the domain lock.
2217 mono_domain_code_foreach (MonoDomain *domain, MonoCodeManagerFunc func, void *user_data)
2219 mono_domain_lock (domain);
2220 mono_code_manager_foreach (domain->code_mp, func, user_data);
2221 mono_domain_unlock (domain);
2226 mono_context_set (MonoAppContext * new_context)
2228 SET_APPCONTEXT (new_context);
2232 mono_context_get (void)
2234 return GET_APPCONTEXT ();
2237 /* LOCKING: the caller holds the lock for this domain */
2239 mono_domain_add_class_static_data (MonoDomain *domain, MonoClass *klass, gpointer data, guint32 *bitmap)
2241 /* The first entry in the array is the index of the next free slot
2242 * and the total size of the array
2245 if (domain->static_data_array) {
2246 int size = GPOINTER_TO_INT (domain->static_data_array [1]);
2247 next = GPOINTER_TO_INT (domain->static_data_array [0]);
2249 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * (size * 2), NULL);
2250 memcpy (new_array, domain->static_data_array, sizeof (gpointer) * size);
2252 new_array [1] = GINT_TO_POINTER (size);
2253 mono_gc_free_fixed (domain->static_data_array);
2254 domain->static_data_array = new_array;
2258 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * size, NULL);
2260 new_array [0] = GINT_TO_POINTER (next);
2261 new_array [1] = GINT_TO_POINTER (size);
2262 domain->static_data_array = new_array;
2264 domain->static_data_array [next++] = data;
2265 domain->static_data_array [0] = GINT_TO_POINTER (next);
2269 mono_get_corlib (void)
2271 return mono_defaults.corlib;
2275 mono_get_object_class (void)
2277 return mono_defaults.object_class;
2281 mono_get_byte_class (void)
2283 return mono_defaults.byte_class;
2287 mono_get_void_class (void)
2289 return mono_defaults.void_class;
2293 mono_get_boolean_class (void)
2295 return mono_defaults.boolean_class;
2299 mono_get_sbyte_class (void)
2301 return mono_defaults.sbyte_class;
2305 mono_get_int16_class (void)
2307 return mono_defaults.int16_class;
2311 mono_get_uint16_class (void)
2313 return mono_defaults.uint16_class;
2317 mono_get_int32_class (void)
2319 return mono_defaults.int32_class;
2323 mono_get_uint32_class (void)
2325 return mono_defaults.uint32_class;
2329 mono_get_intptr_class (void)
2331 return mono_defaults.int_class;
2335 mono_get_uintptr_class (void)
2337 return mono_defaults.uint_class;
2341 mono_get_int64_class (void)
2343 return mono_defaults.int64_class;
2347 mono_get_uint64_class (void)
2349 return mono_defaults.uint64_class;
2353 mono_get_single_class (void)
2355 return mono_defaults.single_class;
2359 mono_get_double_class (void)
2361 return mono_defaults.double_class;
2365 mono_get_char_class (void)
2367 return mono_defaults.char_class;
2371 mono_get_string_class (void)
2373 return mono_defaults.string_class;
2377 mono_get_enum_class (void)
2379 return mono_defaults.enum_class;
2383 mono_get_array_class (void)
2385 return mono_defaults.array_class;
2389 mono_get_thread_class (void)
2391 return mono_defaults.thread_class;
2395 mono_get_exception_class (void)
2397 return mono_defaults.exception_class;
2401 static char* get_attribute_value (const gchar **attribute_names,
2402 const gchar **attribute_values,
2403 const char *att_name)
2406 for (n=0; attribute_names[n] != NULL; n++) {
2407 if (strcmp (attribute_names[n], att_name) == 0)
2408 return g_strdup (attribute_values[n]);
2413 static void start_element (GMarkupParseContext *context,
2414 const gchar *element_name,
2415 const gchar **attribute_names,
2416 const gchar **attribute_values,
2420 AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2422 if (strcmp (element_name, "configuration") == 0) {
2423 app_config->configuration_count++;
2426 if (strcmp (element_name, "startup") == 0) {
2427 app_config->startup_count++;
2431 if (app_config->configuration_count != 1 || app_config->startup_count != 1)
2434 if (strcmp (element_name, "requiredRuntime") == 0) {
2435 app_config->required_runtime = get_attribute_value (attribute_names, attribute_values, "version");
2436 } else if (strcmp (element_name, "supportedRuntime") == 0) {
2437 char *version = get_attribute_value (attribute_names, attribute_values, "version");
2438 app_config->supported_runtimes = g_slist_append (app_config->supported_runtimes, version);
2442 static void end_element (GMarkupParseContext *context,
2443 const gchar *element_name,
2447 AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2449 if (strcmp (element_name, "configuration") == 0) {
2450 app_config->configuration_count--;
2451 } else if (strcmp (element_name, "startup") == 0) {
2452 app_config->startup_count--;
2456 static const GMarkupParser
2465 static AppConfigInfo *
2466 app_config_parse (const char *exe_filename)
2468 AppConfigInfo *app_config;
2469 GMarkupParseContext *context;
2472 const char *bundled_config;
2473 char *config_filename;
2475 bundled_config = mono_config_string_for_assembly_file (exe_filename);
2477 if (bundled_config) {
2478 text = g_strdup (bundled_config);
2479 len = strlen (text);
2481 config_filename = g_strconcat (exe_filename, ".config", NULL);
2483 if (!g_file_get_contents (config_filename, &text, &len, NULL)) {
2484 g_free (config_filename);
2487 g_free (config_filename);
2490 app_config = g_new0 (AppConfigInfo, 1);
2492 context = g_markup_parse_context_new (&mono_parser, 0, app_config, NULL);
2493 if (g_markup_parse_context_parse (context, text, len, NULL)) {
2494 g_markup_parse_context_end_parse (context, NULL);
2496 g_markup_parse_context_free (context);
2502 app_config_free (AppConfigInfo* app_config)
2505 GSList *list = app_config->supported_runtimes;
2506 while (list != NULL) {
2507 rt = (char*)list->data;
2509 list = g_slist_next (list);
2511 g_slist_free (app_config->supported_runtimes);
2512 g_free (app_config->required_runtime);
2513 g_free (app_config);
2517 static const MonoRuntimeInfo*
2518 get_runtime_by_version (const char *version)
2521 int max = G_N_ELEMENTS (supported_runtimes);
2523 for (n=0; n<max; n++) {
2524 if (strcmp (version, supported_runtimes[n].runtime_version) == 0)
2525 return &supported_runtimes[n];
2531 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes)
2533 AppConfigInfo* app_config;
2535 const MonoRuntimeInfo* runtime = NULL;
2536 MonoImage *image = NULL;
2538 app_config = app_config_parse (exe_file);
2540 if (app_config != NULL) {
2541 /* Check supportedRuntime elements, if none is supported, fail.
2542 * If there are no such elements, look for a requiredRuntime element.
2544 if (app_config->supported_runtimes != NULL) {
2546 GSList *list = app_config->supported_runtimes;
2547 while (list != NULL) {
2548 version = (char*) list->data;
2549 runtime = get_runtime_by_version (version);
2550 if (runtime != NULL)
2551 runtimes [n++] = runtime;
2552 list = g_slist_next (list);
2554 runtimes [n] = NULL;
2555 app_config_free (app_config);
2559 /* Check the requiredRuntime element. This is for 1.0 apps only. */
2560 if (app_config->required_runtime != NULL) {
2561 runtimes [0] = get_runtime_by_version (app_config->required_runtime);
2562 runtimes [1] = NULL;
2563 app_config_free (app_config);
2566 app_config_free (app_config);
2569 /* Look for a runtime with the exact version */
2570 image = mono_assembly_open_from_bundle (exe_file, NULL, FALSE);
2573 image = mono_image_open (exe_file, NULL);
2575 if (image == NULL) {
2576 /* The image is wrong or the file was not found. In this case return
2577 * a default runtime and leave to the initialization method the work of
2578 * reporting the error.
2580 runtimes [0] = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
2581 runtimes [1] = NULL;
2587 runtimes [0] = get_runtime_by_version (image->version);
2588 runtimes [1] = NULL;
2593 * mono_get_runtime_info:
2595 * Returns: the version of the current runtime instance.
2597 const MonoRuntimeInfo*
2598 mono_get_runtime_info (void)
2600 return current_runtime;
2604 mono_debugger_check_runtime_version (const char *filename)
2606 const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
2607 const MonoRuntimeInfo *rinfo;
2610 get_runtimes_from_exe (filename, &image, runtimes);
2611 rinfo = runtimes [0];
2614 return g_strdup_printf ("Cannot get runtime version from assembly `%s'", filename);
2616 if (rinfo != current_runtime)
2617 return g_strdup_printf ("The Mono Debugger is currently using the `%s' runtime, but "
2618 "the assembly `%s' requires version `%s'", current_runtime->runtime_version,
2619 filename, rinfo->runtime_version);
2625 * mono_framework_version:
2627 * Return the major version of the framework curently executing.
2630 mono_framework_version (void)
2632 return current_runtime->framework_version [0] - '0';