2 * domain.c: MonoDomain functions
5 * Dietmar Maurer (dietmar@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
10 * Copyright 2011-2012 Xamarin, Inc (http://www.xamarin.com)
18 #include <mono/metadata/gc-internal.h>
20 #include <mono/utils/mono-compiler.h>
21 #include <mono/utils/mono-logger-internal.h>
22 #include <mono/utils/mono-membar.h>
23 #include <mono/utils/mono-counters.h>
24 #include <mono/utils/hazard-pointer.h>
25 #include <mono/utils/mono-tls.h>
26 #include <mono/metadata/object.h>
27 #include <mono/metadata/object-internals.h>
28 #include <mono/metadata/domain-internals.h>
29 #include <mono/metadata/class-internals.h>
30 #include <mono/metadata/assembly.h>
31 #include <mono/metadata/exception.h>
32 #include <mono/metadata/metadata-internals.h>
33 #include <mono/metadata/gc-internal.h>
34 #include <mono/metadata/appdomain.h>
35 #include <mono/metadata/mono-debug-debugger.h>
36 #include <mono/metadata/mono-config.h>
37 #include <mono/metadata/threads-types.h>
38 #include <mono/metadata/runtime.h>
39 #include <metadata/threads.h>
40 #include <metadata/profiler-private.h>
41 #include <mono/metadata/coree.h>
43 /* #define DEBUG_DOMAIN_UNLOAD */
45 /* we need to use both the Tls* functions and __thread because
46 * some archs may generate faster jit code with one meachanism
47 * or the other (we used to do it because tls slots were GC-tracked,
48 * but we can't depend on this).
50 static MonoNativeTlsKey appdomain_thread_id;
52 #ifdef MONO_HAVE_FAST_TLS
54 MONO_FAST_TLS_DECLARE(tls_appdomain);
56 #define GET_APPDOMAIN() ((MonoDomain*)MONO_FAST_TLS_GET(tls_appdomain))
58 #define SET_APPDOMAIN(x) do { \
59 MONO_FAST_TLS_SET (tls_appdomain,x); \
60 mono_native_tls_set_value (appdomain_thread_id, x); \
61 mono_gc_set_current_thread_appdomain (x); \
64 #else /* !MONO_HAVE_FAST_TLS */
66 #define GET_APPDOMAIN() ((MonoDomain *)mono_native_tls_get_value (appdomain_thread_id))
67 #define SET_APPDOMAIN(x) do { \
68 mono_native_tls_set_value (appdomain_thread_id, x); \
69 mono_gc_set_current_thread_appdomain (x); \
74 #define GET_APPCONTEXT() (mono_thread_internal_current ()->current_appcontext)
75 #define SET_APPCONTEXT(x) MONO_OBJECT_SETREF (mono_thread_internal_current (), current_appcontext, (x))
77 static guint16 appdomain_list_size = 0;
78 static guint16 appdomain_next = 0;
79 static MonoDomain **appdomains_list = NULL;
80 static MonoImage *exe_image;
82 gboolean mono_dont_free_domains;
84 #define mono_appdomains_lock() EnterCriticalSection (&appdomains_mutex)
85 #define mono_appdomains_unlock() LeaveCriticalSection (&appdomains_mutex)
86 static CRITICAL_SECTION appdomains_mutex;
88 static MonoDomain *mono_root_domain = NULL;
91 static int max_domain_code_size = 0;
92 static int max_domain_code_alloc = 0;
93 static int total_domain_code_alloc = 0;
95 /* AppConfigInfo: Information about runtime versions supported by an
99 GSList *supported_runtimes;
100 char *required_runtime;
101 int configuration_count;
106 * AotModuleInfo: Contains information about AOT modules.
113 static const MonoRuntimeInfo *current_runtime = NULL;
115 static MonoJitInfoFindInAot jit_info_find_in_aot_func = NULL;
118 * Contains information about AOT loaded code.
120 static MonoAotModuleInfoTable *aot_modules = NULL;
122 /* This is the list of runtime versions supported by this JIT.
124 static const MonoRuntimeInfo supported_runtimes[] = {
125 {"v2.0.50215","2.0", { {2,0,0,0}, { 8,0,0,0}, {3,5,0,0}, {3,0,0,0} } },
126 {"v2.0.50727","2.0", { {2,0,0,0}, { 8,0,0,0}, {3,5,0,0}, {3,0,0,0} } },
127 {"v4.0.30319","4.5", { {4,0,0,0}, {10,0,0,0}, {4,0,0,0}, {4,0,0,0} } },
128 {"v4.0.30128","4.0", { {4,0,0,0}, {10,0,0,0}, {4,0,0,0}, {4,0,0,0} } },
129 {"v4.0.20506","4.0", { {4,0,0,0}, {10,0,0,0}, {4,0,0,0}, {4,0,0,0} } },
130 {"moonlight", "2.1", { {2,0,5,0}, { 9,0,0,0}, {3,5,0,0}, {3,0,0,0} } },
134 /* The stable runtime version */
135 #define DEFAULT_RUNTIME_VERSION "v2.0.50727"
137 /* Callbacks installed by the JIT */
138 static MonoCreateDomainFunc create_domain_hook;
139 static MonoFreeDomainFunc free_domain_hook;
141 /* This is intentionally not in the header file, so people don't misuse it. */
142 extern void _mono_debug_init_corlib (MonoDomain *domain);
145 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes);
147 static const MonoRuntimeInfo*
148 get_runtime_by_version (const char *version);
151 mono_jit_info_find_aot_module (guint8* addr);
154 mono_domain_get_tls_key (void)
156 return appdomain_thread_id;
160 mono_domain_get_tls_offset (void)
163 MONO_THREAD_VAR_OFFSET (tls_appdomain, offset);
164 /* __asm ("jmp 1f; .section writetext, \"awx\"; 1: movl $tls_appdomain@ntpoff, %0; jmp 2f; .previous; 2:"
169 #define JIT_INFO_TABLE_FILL_RATIO_NOM 3
170 #define JIT_INFO_TABLE_FILL_RATIO_DENOM 4
171 #define JIT_INFO_TABLE_FILLED_NUM_ELEMENTS (MONO_JIT_INFO_TABLE_CHUNK_SIZE * JIT_INFO_TABLE_FILL_RATIO_NOM / JIT_INFO_TABLE_FILL_RATIO_DENOM)
173 #define JIT_INFO_TABLE_LOW_WATERMARK(n) ((n) / 2)
174 #define JIT_INFO_TABLE_HIGH_WATERMARK(n) ((n) * 5 / 6)
176 #define JIT_INFO_TOMBSTONE_MARKER ((MonoMethod*)NULL)
177 #define IS_JIT_INFO_TOMBSTONE(ji) ((ji)->method == JIT_INFO_TOMBSTONE_MARKER)
179 #define JIT_INFO_TABLE_HAZARD_INDEX 0
180 #define JIT_INFO_HAZARD_INDEX 1
183 jit_info_table_num_elements (MonoJitInfoTable *table)
186 int num_elements = 0;
188 for (i = 0; i < table->num_chunks; ++i) {
189 MonoJitInfoTableChunk *chunk = table->chunks [i];
190 int chunk_num_elements = chunk->num_elements;
193 for (j = 0; j < chunk_num_elements; ++j) {
194 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j]))
202 static MonoJitInfoTableChunk*
203 jit_info_table_new_chunk (void)
205 MonoJitInfoTableChunk *chunk = g_new0 (MonoJitInfoTableChunk, 1);
211 static MonoJitInfoTable *
212 jit_info_table_new (MonoDomain *domain)
214 MonoJitInfoTable *table = g_malloc0 (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*));
216 table->domain = domain;
217 table->num_chunks = 1;
218 table->chunks [0] = jit_info_table_new_chunk ();
224 jit_info_table_free (MonoJitInfoTable *table)
227 int num_chunks = table->num_chunks;
228 MonoDomain *domain = table->domain;
230 mono_domain_lock (domain);
232 table->domain->num_jit_info_tables--;
233 if (table->domain->num_jit_info_tables <= 1) {
236 for (list = table->domain->jit_info_free_queue; list; list = list->next)
239 g_slist_free (table->domain->jit_info_free_queue);
240 table->domain->jit_info_free_queue = NULL;
243 /* At this point we assume that there are no other threads
244 still accessing the table, so we don't have to worry about
245 hazardous pointers. */
247 for (i = 0; i < num_chunks; ++i) {
248 MonoJitInfoTableChunk *chunk = table->chunks [i];
252 if (--chunk->refcount > 0)
255 num_elements = chunk->num_elements;
256 for (j = 0; j < num_elements; ++j) {
257 MonoJitInfo *ji = chunk->data [j];
259 if (IS_JIT_INFO_TOMBSTONE (ji))
266 mono_domain_unlock (domain);
271 /* The jit_info_table is sorted in ascending order by the end
272 * addresses of the compiled methods. The reason why we have to do
273 * this is that once we introduce tombstones, it becomes possible for
274 * code ranges to overlap, and if we sort by code start and insert at
275 * the back of the table, we cannot guarantee that we won't overlook
278 * There are actually two possible ways to do the sorting and
279 * inserting which work with our lock-free mechanism:
281 * 1. Sort by start address and insert at the front. When looking for
282 * an entry, find the last one with a start address lower than the one
283 * you're looking for, then work your way to the front of the table.
285 * 2. Sort by end address and insert at the back. When looking for an
286 * entry, find the first one with an end address higher than the one
287 * you're looking for, then work your way to the end of the table.
289 * We chose the latter out of convenience.
292 jit_info_table_index (MonoJitInfoTable *table, gint8 *addr)
294 int left = 0, right = table->num_chunks;
296 g_assert (left < right);
299 int pos = (left + right) / 2;
300 MonoJitInfoTableChunk *chunk = table->chunks [pos];
302 if (addr < chunk->last_code_end)
306 } while (left < right);
307 g_assert (left == right);
309 if (left >= table->num_chunks)
310 return table->num_chunks - 1;
315 jit_info_table_chunk_index (MonoJitInfoTableChunk *chunk, MonoThreadHazardPointers *hp, gint8 *addr)
317 int left = 0, right = chunk->num_elements;
319 while (left < right) {
320 int pos = (left + right) / 2;
321 MonoJitInfo *ji = get_hazardous_pointer((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
322 gint8 *code_end = (gint8*)ji->code_start + ji->code_size;
329 g_assert (left == right);
335 mono_jit_info_table_find (MonoDomain *domain, char *addr)
337 MonoJitInfoTable *table;
340 MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
343 ++mono_stats.jit_info_table_lookup_count;
345 /* First we have to get the domain's jit_info_table. This is
346 complicated by the fact that a writer might substitute a
347 new table and free the old one. What the writer guarantees
348 us is that it looks at the hazard pointers after it has
349 changed the jit_info_table pointer. So, if we guard the
350 table by a hazard pointer and make sure that the pointer is
351 still there after we've made it hazardous, we don't have to
352 worry about the writer freeing the table. */
353 table = get_hazardous_pointer ((gpointer volatile*)&domain->jit_info_table, hp, JIT_INFO_TABLE_HAZARD_INDEX);
355 chunk_pos = jit_info_table_index (table, (gint8*)addr);
356 g_assert (chunk_pos < table->num_chunks);
358 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], hp, (gint8*)addr);
360 /* We now have a position that's very close to that of the
361 first element whose end address is higher than the one
362 we're looking for. If we don't have the exact position,
363 then we have a position below that one, so we'll just
364 search upward until we find our element. */
366 MonoJitInfoTableChunk *chunk = table->chunks [chunk_pos];
368 while (pos < chunk->num_elements) {
369 ji = get_hazardous_pointer ((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
373 if (IS_JIT_INFO_TOMBSTONE (ji)) {
374 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
377 if ((gint8*)addr >= (gint8*)ji->code_start
378 && (gint8*)addr < (gint8*)ji->code_start + ji->code_size) {
379 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
380 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
384 /* If we find a non-tombstone element which is already
385 beyond what we're looking for, we have to end the
387 if ((gint8*)addr < (gint8*)ji->code_start)
393 } while (chunk_pos < table->num_chunks);
399 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
400 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
404 /* Maybe its an AOT module */
405 image = mono_jit_info_find_aot_module ((guint8*)addr);
407 ji = jit_info_find_in_aot_func (domain, image, addr);
412 static G_GNUC_UNUSED void
413 jit_info_table_check (MonoJitInfoTable *table)
417 for (i = 0; i < table->num_chunks; ++i) {
418 MonoJitInfoTableChunk *chunk = table->chunks [i];
421 g_assert (chunk->refcount > 0 /* && chunk->refcount <= 8 */);
422 if (chunk->refcount > 10)
423 printf("warning: chunk refcount is %d\n", chunk->refcount);
424 g_assert (chunk->num_elements <= MONO_JIT_INFO_TABLE_CHUNK_SIZE);
426 for (j = 0; j < chunk->num_elements; ++j) {
427 MonoJitInfo *this = chunk->data [j];
430 g_assert ((gint8*)this->code_start + this->code_size <= chunk->last_code_end);
432 if (j < chunk->num_elements - 1)
433 next = chunk->data [j + 1];
434 else if (i < table->num_chunks - 1) {
437 for (k = i + 1; k < table->num_chunks; ++k)
438 if (table->chunks [k]->num_elements > 0)
441 if (k >= table->num_chunks)
444 g_assert (table->chunks [k]->num_elements > 0);
445 next = table->chunks [k]->data [0];
449 g_assert ((gint8*)this->code_start + this->code_size <= (gint8*)next->code_start + next->code_size);
454 static MonoJitInfoTable*
455 jit_info_table_realloc (MonoJitInfoTable *old)
458 int num_elements = jit_info_table_num_elements (old);
461 int new_chunk, new_element;
462 MonoJitInfoTable *new;
464 /* number of needed places for elements needed */
465 required_size = (int)((long)num_elements * JIT_INFO_TABLE_FILL_RATIO_DENOM / JIT_INFO_TABLE_FILL_RATIO_NOM);
466 num_chunks = (required_size + MONO_JIT_INFO_TABLE_CHUNK_SIZE - 1) / MONO_JIT_INFO_TABLE_CHUNK_SIZE;
467 if (num_chunks == 0) {
468 g_assert (num_elements == 0);
469 return jit_info_table_new (old->domain);
471 g_assert (num_chunks > 0);
473 new = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*) * num_chunks);
474 new->domain = old->domain;
475 new->num_chunks = num_chunks;
477 for (i = 0; i < num_chunks; ++i)
478 new->chunks [i] = jit_info_table_new_chunk ();
482 for (i = 0; i < old->num_chunks; ++i) {
483 MonoJitInfoTableChunk *chunk = old->chunks [i];
484 int chunk_num_elements = chunk->num_elements;
487 for (j = 0; j < chunk_num_elements; ++j) {
488 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j])) {
489 g_assert (new_chunk < num_chunks);
490 new->chunks [new_chunk]->data [new_element] = chunk->data [j];
491 if (++new_element >= JIT_INFO_TABLE_FILLED_NUM_ELEMENTS) {
492 new->chunks [new_chunk]->num_elements = new_element;
500 if (new_chunk < num_chunks) {
501 g_assert (new_chunk == num_chunks - 1);
502 new->chunks [new_chunk]->num_elements = new_element;
503 g_assert (new->chunks [new_chunk]->num_elements > 0);
506 for (i = 0; i < num_chunks; ++i) {
507 MonoJitInfoTableChunk *chunk = new->chunks [i];
508 MonoJitInfo *ji = chunk->data [chunk->num_elements - 1];
510 new->chunks [i]->last_code_end = (gint8*)ji->code_start + ji->code_size;
517 jit_info_table_split_chunk (MonoJitInfoTableChunk *chunk, MonoJitInfoTableChunk **new1p, MonoJitInfoTableChunk **new2p)
519 MonoJitInfoTableChunk *new1 = jit_info_table_new_chunk ();
520 MonoJitInfoTableChunk *new2 = jit_info_table_new_chunk ();
522 g_assert (chunk->num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE);
524 new1->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE / 2;
525 new2->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE - new1->num_elements;
527 memcpy ((void*)new1->data, (void*)chunk->data, sizeof (MonoJitInfo*) * new1->num_elements);
528 memcpy ((void*)new2->data, (void*)(chunk->data + new1->num_elements), sizeof (MonoJitInfo*) * new2->num_elements);
530 new1->last_code_end = (gint8*)new1->data [new1->num_elements - 1]->code_start
531 + new1->data [new1->num_elements - 1]->code_size;
532 new2->last_code_end = (gint8*)new2->data [new2->num_elements - 1]->code_start
533 + new2->data [new2->num_elements - 1]->code_size;
539 static MonoJitInfoTable*
540 jit_info_table_copy_and_split_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
542 MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
543 + sizeof (MonoJitInfoTableChunk*) * (table->num_chunks + 1));
546 new_table->domain = table->domain;
547 new_table->num_chunks = table->num_chunks + 1;
550 for (i = 0; i < table->num_chunks; ++i) {
551 if (table->chunks [i] == chunk) {
552 jit_info_table_split_chunk (chunk, &new_table->chunks [j], &new_table->chunks [j + 1]);
555 new_table->chunks [j] = table->chunks [i];
556 ++new_table->chunks [j]->refcount;
561 g_assert (j == new_table->num_chunks);
566 static MonoJitInfoTableChunk*
567 jit_info_table_purify_chunk (MonoJitInfoTableChunk *old)
569 MonoJitInfoTableChunk *new = jit_info_table_new_chunk ();
573 for (i = 0; i < old->num_elements; ++i) {
574 if (!IS_JIT_INFO_TOMBSTONE (old->data [i]))
575 new->data [j++] = old->data [i];
578 new->num_elements = j;
579 if (new->num_elements > 0)
580 new->last_code_end = (gint8*)new->data [j - 1]->code_start + new->data [j - 1]->code_size;
582 new->last_code_end = old->last_code_end;
587 static MonoJitInfoTable*
588 jit_info_table_copy_and_purify_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
590 MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
591 + sizeof (MonoJitInfoTableChunk*) * table->num_chunks);
594 new_table->domain = table->domain;
595 new_table->num_chunks = table->num_chunks;
598 for (i = 0; i < table->num_chunks; ++i) {
599 if (table->chunks [i] == chunk)
600 new_table->chunks [j++] = jit_info_table_purify_chunk (table->chunks [i]);
602 new_table->chunks [j] = table->chunks [i];
603 ++new_table->chunks [j]->refcount;
608 g_assert (j == new_table->num_chunks);
613 /* As we add an element to the table the case can arise that the chunk
614 * to which we need to add is already full. In that case we have to
615 * allocate a new table and do something about that chunk. We have
616 * several strategies:
618 * If the number of elements in the table is below the low watermark
619 * or above the high watermark, we reallocate the whole table.
620 * Otherwise we only concern ourselves with the overflowing chunk:
622 * If there are no tombstones in the chunk then we split the chunk in
623 * two, each half full.
625 * If the chunk does contain tombstones, we just make a new copy of
626 * the chunk without the tombstones, which will have room for at least
627 * the one element we have to add.
629 static MonoJitInfoTable*
630 jit_info_table_chunk_overflow (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
632 int num_elements = jit_info_table_num_elements (table);
635 if (num_elements < JIT_INFO_TABLE_LOW_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)
636 || num_elements > JIT_INFO_TABLE_HIGH_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)) {
637 //printf ("reallocing table\n");
638 return jit_info_table_realloc (table);
641 /* count the number of non-tombstone elements in the chunk */
643 for (i = 0; i < chunk->num_elements; ++i) {
644 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [i]))
648 if (num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
649 //printf ("splitting chunk\n");
650 return jit_info_table_copy_and_split_chunk (table, chunk);
653 //printf ("purifying chunk\n");
654 return jit_info_table_copy_and_purify_chunk (table, chunk);
657 /* We add elements to the table by first making space for them by
658 * shifting the elements at the back to the right, one at a time.
659 * This results in duplicate entries during the process, but during
660 * all the time the table is in a sorted state. Also, when an element
661 * is replaced by another one, the element that replaces it has an end
662 * address that is equal to or lower than that of the replaced
663 * element. That property is necessary to guarantee that when
664 * searching for an element we end up at a position not higher than
665 * the one we're looking for (i.e. we either find the element directly
666 * or we end up to the left of it).
669 mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
671 MonoJitInfoTable *table;
673 MonoJitInfoTableChunk *chunk;
677 g_assert (ji->method != NULL);
679 mono_domain_lock (domain);
681 ++mono_stats.jit_info_table_insert_count;
683 table = domain->jit_info_table;
686 chunk_pos = jit_info_table_index (table, (gint8*)ji->code_start + ji->code_size);
687 g_assert (chunk_pos < table->num_chunks);
688 chunk = table->chunks [chunk_pos];
690 if (chunk->num_elements >= MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
691 MonoJitInfoTable *new_table = jit_info_table_chunk_overflow (table, chunk);
693 /* Debugging code, should be removed. */
694 //jit_info_table_check (new_table);
696 domain->jit_info_table = new_table;
697 mono_memory_barrier ();
698 domain->num_jit_info_tables++;
699 mono_thread_hazardous_free_or_queue (table, (MonoHazardousFreeFunc)jit_info_table_free, TRUE, FALSE);
705 /* Debugging code, should be removed. */
706 //jit_info_table_check (table);
708 num_elements = chunk->num_elements;
710 pos = jit_info_table_chunk_index (chunk, NULL, (gint8*)ji->code_start + ji->code_size);
712 /* First we need to size up the chunk by one, by copying the
713 last item, or inserting the first one, if the table is
715 if (num_elements > 0)
716 chunk->data [num_elements] = chunk->data [num_elements - 1];
718 chunk->data [0] = ji;
719 mono_memory_write_barrier ();
720 chunk->num_elements = ++num_elements;
722 /* Shift the elements up one by one. */
723 for (i = num_elements - 2; i >= pos; --i) {
724 mono_memory_write_barrier ();
725 chunk->data [i + 1] = chunk->data [i];
728 /* Now we have room and can insert the new item. */
729 mono_memory_write_barrier ();
730 chunk->data [pos] = ji;
732 /* Set the high code end address chunk entry. */
733 chunk->last_code_end = (gint8*)chunk->data [chunk->num_elements - 1]->code_start
734 + chunk->data [chunk->num_elements - 1]->code_size;
736 /* Debugging code, should be removed. */
737 //jit_info_table_check (table);
739 mono_domain_unlock (domain);
743 mono_jit_info_make_tombstone (MonoJitInfo *ji)
745 MonoJitInfo *tombstone = g_new0 (MonoJitInfo, 1);
747 tombstone->code_start = ji->code_start;
748 tombstone->code_size = ji->code_size;
749 tombstone->method = JIT_INFO_TOMBSTONE_MARKER;
755 * LOCKING: domain lock
758 mono_jit_info_free_or_queue (MonoDomain *domain, MonoJitInfo *ji)
760 if (domain->num_jit_info_tables <= 1) {
761 /* Can it actually happen that we only have one table
762 but ji is still hazardous? */
763 mono_thread_hazardous_free_or_queue (ji, g_free, TRUE, FALSE);
765 domain->jit_info_free_queue = g_slist_prepend (domain->jit_info_free_queue, ji);
770 mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
772 MonoJitInfoTable *table;
773 MonoJitInfoTableChunk *chunk;
774 gpointer start = ji->code_start;
777 mono_domain_lock (domain);
778 table = domain->jit_info_table;
780 ++mono_stats.jit_info_table_remove_count;
782 chunk_pos = jit_info_table_index (table, start);
783 g_assert (chunk_pos < table->num_chunks);
785 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], NULL, start);
788 chunk = table->chunks [chunk_pos];
790 while (pos < chunk->num_elements) {
791 if (chunk->data [pos] == ji)
794 g_assert (IS_JIT_INFO_TOMBSTONE (chunk->data [pos]));
795 g_assert ((guint8*)chunk->data [pos]->code_start + chunk->data [pos]->code_size
796 <= (guint8*)ji->code_start + ji->code_size);
803 } while (chunk_pos < table->num_chunks);
806 g_assert (chunk->data [pos] == ji);
808 chunk->data [pos] = mono_jit_info_make_tombstone (ji);
810 /* Debugging code, should be removed. */
811 //jit_info_table_check (table);
813 mono_jit_info_free_or_queue (domain, ji);
815 mono_domain_unlock (domain);
818 static MonoAotModuleInfoTable*
819 mono_aot_module_info_table_new (void)
821 return g_array_new (FALSE, FALSE, sizeof (gpointer));
825 aot_info_table_index (MonoAotModuleInfoTable *table, char *addr)
827 int left = 0, right = table->len;
829 while (left < right) {
830 int pos = (left + right) / 2;
831 AotModuleInfo *ainfo = g_array_index (table, gpointer, pos);
832 char *start = ainfo->start;
833 char *end = ainfo->end;
837 else if (addr >= end)
847 mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
849 AotModuleInfo *ainfo = g_new0 (AotModuleInfo, 1);
852 ainfo->image = image;
853 ainfo->start = start;
856 mono_appdomains_lock ();
859 aot_modules = mono_aot_module_info_table_new ();
861 pos = aot_info_table_index (aot_modules, start);
863 g_array_insert_val (aot_modules, pos, ainfo);
865 mono_appdomains_unlock ();
869 mono_jit_info_find_aot_module (guint8* addr)
871 guint left = 0, right;
876 mono_appdomains_lock ();
878 right = aot_modules->len;
879 while (left < right) {
880 guint pos = (left + right) / 2;
881 AotModuleInfo *ai = g_array_index (aot_modules, gpointer, pos);
883 if (addr < (guint8*)ai->start)
885 else if (addr >= (guint8*)ai->end)
888 mono_appdomains_unlock ();
893 mono_appdomains_unlock ();
899 mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func)
901 jit_info_find_in_aot_func = func;
905 mono_jit_info_get_code_start (MonoJitInfo* ji)
907 return ji->code_start;
911 mono_jit_info_get_code_size (MonoJitInfo* ji)
913 return ji->code_size;
917 mono_jit_info_get_method (MonoJitInfo* ji)
923 jit_info_key_extract (gpointer value)
925 MonoJitInfo *info = (MonoJitInfo*)value;
931 jit_info_next_value (gpointer value)
933 MonoJitInfo *info = (MonoJitInfo*)value;
935 return (gpointer*)&info->next_jit_code_hash;
939 mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
941 mono_internal_hash_table_init (jit_code_hash,
942 mono_aligned_addr_hash,
943 jit_info_key_extract,
944 jit_info_next_value);
948 mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
950 if (ji->has_generic_jit_info)
951 return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
957 * mono_jit_info_get_generic_sharing_context:
960 * Returns the jit info's generic sharing context, or NULL if it
963 MonoGenericSharingContext*
964 mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
966 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
969 return gi->generic_sharing_context;
975 * mono_jit_info_set_generic_sharing_context:
977 * @gsctx: a generic sharing context
979 * Sets the jit info's generic sharing context. The jit info must
980 * have memory allocated for the context.
983 mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
985 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
989 gi->generic_sharing_context = gsctx;
992 MonoTryBlockHoleTableJitInfo*
993 mono_jit_info_get_try_block_hole_table_info (MonoJitInfo *ji)
995 if (ji->has_try_block_holes) {
996 char *ptr = (char*)&ji->clauses [ji->num_clauses];
997 if (ji->has_generic_jit_info)
998 ptr += sizeof (MonoGenericJitInfo);
999 return (MonoTryBlockHoleTableJitInfo*)ptr;
1006 mono_jit_info_get_arch_eh_info (MonoJitInfo *ji)
1008 if (ji->has_arch_eh_info) {
1009 char *ptr = (char*)&ji->clauses [ji->num_clauses];
1010 if (ji->has_generic_jit_info)
1011 ptr += sizeof (MonoGenericJitInfo);
1012 if (ji->has_try_block_holes)
1013 ptr += sizeof (MonoTryBlockHoleTableJitInfo);
1014 return (MonoArchEHJitInfo*)ptr;
1021 mono_jit_info_get_cas_info (MonoJitInfo *ji)
1023 if (ji->has_cas_info) {
1024 char *ptr = (char*)&ji->clauses [ji->num_clauses];
1025 if (ji->has_generic_jit_info)
1026 ptr += sizeof (MonoGenericJitInfo);
1027 if (ji->has_try_block_holes)
1028 ptr += sizeof (MonoTryBlockHoleTableJitInfo);
1029 if (ji->has_arch_eh_info)
1030 ptr += sizeof (MonoArchEHJitInfo);
1031 return (MonoMethodCasInfo*)ptr;
1038 mono_install_create_domain_hook (MonoCreateDomainFunc func)
1040 create_domain_hook = func;
1044 mono_install_free_domain_hook (MonoFreeDomainFunc func)
1046 free_domain_hook = func;
1050 * mono_string_equal:
1051 * @s1: First string to compare
1052 * @s2: Second string to compare
1054 * Returns FALSE if the strings differ.
1057 mono_string_equal (MonoString *s1, MonoString *s2)
1059 int l1 = mono_string_length (s1);
1060 int l2 = mono_string_length (s2);
1067 return memcmp (mono_string_chars (s1), mono_string_chars (s2), l1 * 2) == 0;
1072 * @s: the string to hash
1074 * Returns the hash for the string.
1077 mono_string_hash (MonoString *s)
1079 const guint16 *p = mono_string_chars (s);
1080 int i, len = mono_string_length (s);
1083 for (i = 0; i < len; i++) {
1084 h = (h << 5) - h + *p;
1092 mono_ptrarray_equal (gpointer *s1, gpointer *s2)
1094 int len = GPOINTER_TO_INT (s1 [0]);
1095 if (len != GPOINTER_TO_INT (s2 [0]))
1098 return memcmp (s1 + 1, s2 + 1, len * sizeof(gpointer)) == 0;
1102 mono_ptrarray_hash (gpointer *s)
1105 int len = GPOINTER_TO_INT (s [0]);
1108 for (i = 1; i < len; i++)
1109 hash += GPOINTER_TO_UINT (s [i]);
1115 * Allocate an id for domain and set domain->domain_id.
1116 * LOCKING: must be called while holding appdomains_mutex.
1117 * We try to assign low numbers to the domain, so it can be used
1118 * as an index in data tables to lookup domain-specific info
1119 * with minimal memory overhead. We also try not to reuse the
1120 * same id too quickly (to help debugging).
1123 domain_id_alloc (MonoDomain *domain)
1126 if (!appdomains_list) {
1127 appdomain_list_size = 2;
1128 appdomains_list = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1130 for (i = appdomain_next; i < appdomain_list_size; ++i) {
1131 if (!appdomains_list [i]) {
1137 for (i = 0; i < appdomain_next; ++i) {
1138 if (!appdomains_list [i]) {
1145 MonoDomain **new_list;
1146 int new_size = appdomain_list_size * 2;
1147 if (new_size >= (1 << 16))
1148 g_assert_not_reached ();
1149 id = appdomain_list_size;
1150 new_list = mono_gc_alloc_fixed (new_size * sizeof (void*), NULL);
1151 memcpy (new_list, appdomains_list, appdomain_list_size * sizeof (void*));
1152 mono_gc_free_fixed (appdomains_list);
1153 appdomains_list = new_list;
1154 appdomain_list_size = new_size;
1156 domain->domain_id = id;
1157 appdomains_list [id] = domain;
1159 if (appdomain_next > appdomain_list_size)
1164 static gsize domain_gc_bitmap [sizeof(MonoDomain)/4/32 + 1];
1165 static gpointer domain_gc_desc = NULL;
1166 static guint32 domain_shadow_serial = 0L;
1169 mono_domain_create (void)
1172 guint32 shadow_serial;
1174 mono_appdomains_lock ();
1175 shadow_serial = domain_shadow_serial++;
1177 if (!domain_gc_desc) {
1178 unsigned int i, bit = 0;
1179 for (i = G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_OBJECT); i < G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_GC_TRACKED); i += sizeof (gpointer)) {
1180 bit = i / sizeof (gpointer);
1181 domain_gc_bitmap [bit / 32] |= (gsize) 1 << (bit % 32);
1183 domain_gc_desc = mono_gc_make_descr_from_bitmap ((gsize*)domain_gc_bitmap, bit + 1);
1185 mono_appdomains_unlock ();
1187 #ifdef HAVE_BOEHM_GC
1189 * Boehm doesn't like roots inside GC allocated objects, and alloc_fixed returns
1190 * a GC_MALLOC-ed object, contrary to the api docs. This causes random crashes when
1191 * running the corlib test suite.
1192 * To solve this, we pass a NULL descriptor, and don't register roots.
1194 domain = mono_gc_alloc_fixed (sizeof (MonoDomain), NULL);
1196 domain = mono_gc_alloc_fixed (sizeof (MonoDomain), domain_gc_desc);
1197 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);
1199 domain->shadow_serial = shadow_serial;
1200 domain->domain = NULL;
1201 domain->setup = NULL;
1202 domain->friendly_name = NULL;
1203 domain->search_path = NULL;
1205 mono_profiler_appdomain_event (domain, MONO_PROFILE_START_LOAD);
1207 domain->mp = mono_mempool_new ();
1208 domain->code_mp = mono_code_manager_new ();
1209 domain->env = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1210 domain->domain_assemblies = NULL;
1211 domain->assembly_bindings = NULL;
1212 domain->assembly_bindings_parsed = FALSE;
1213 domain->class_vtable_array = g_ptr_array_new ();
1214 domain->proxy_vtable_hash = g_hash_table_new ((GHashFunc)mono_ptrarray_hash, (GCompareFunc)mono_ptrarray_equal);
1215 domain->static_data_array = NULL;
1216 mono_jit_code_hash_init (&domain->jit_code_hash);
1217 domain->ldstr_table = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1218 domain->num_jit_info_tables = 1;
1219 domain->jit_info_table = jit_info_table_new (domain);
1220 domain->jit_info_free_queue = NULL;
1221 domain->finalizable_objects_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1222 domain->ftnptrs_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1224 InitializeCriticalSection (&domain->lock);
1225 InitializeCriticalSection (&domain->assemblies_lock);
1226 InitializeCriticalSection (&domain->jit_code_hash_lock);
1227 InitializeCriticalSection (&domain->finalizable_objects_hash_lock);
1229 domain->method_rgctx_hash = NULL;
1231 mono_appdomains_lock ();
1232 domain_id_alloc (domain);
1233 mono_appdomains_unlock ();
1235 #ifndef DISABLE_PERFCOUNTERS
1236 mono_perfcounters->loader_appdomains++;
1237 mono_perfcounters->loader_total_appdomains++;
1240 mono_debug_domain_create (domain);
1242 if (create_domain_hook)
1243 create_domain_hook (domain);
1245 mono_profiler_appdomain_loaded (domain, MONO_PROFILE_OK);
1251 * mono_init_internal:
1253 * Creates the initial application domain and initializes the mono_defaults
1255 * This function is guaranteed to not run any IL code.
1256 * If exe_filename is not NULL, the method will determine the required runtime
1257 * from the exe configuration file or the version PE field.
1258 * If runtime_version is not NULL, that runtime version will be used.
1259 * Either exe_filename or runtime_version must be provided.
1261 * Returns: the initial domain.
1264 mono_init_internal (const char *filename, const char *exe_filename, const char *runtime_version)
1266 static MonoDomain *domain = NULL;
1267 MonoAssembly *ass = NULL;
1268 MonoImageOpenStatus status = MONO_IMAGE_OK;
1269 const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
1273 g_assert_not_reached ();
1276 /* Avoid system error message boxes. */
1277 SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1284 #ifndef DISABLE_PERFCOUNTERS
1285 mono_perfcounters_init ();
1288 mono_counters_register ("Max native code in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_size);
1289 mono_counters_register ("Max code space allocated in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_alloc);
1290 mono_counters_register ("Total code space allocated", MONO_COUNTER_INT|MONO_COUNTER_JIT, &total_domain_code_alloc);
1292 mono_gc_base_init ();
1294 MONO_FAST_TLS_INIT (tls_appdomain);
1295 mono_native_tls_alloc (&appdomain_thread_id, NULL);
1297 InitializeCriticalSection (&appdomains_mutex);
1299 mono_metadata_init ();
1300 mono_images_init ();
1301 mono_assemblies_init ();
1302 mono_classes_init ();
1303 mono_loader_init ();
1304 mono_reflection_init ();
1305 mono_runtime_init_tls ();
1307 /* FIXME: When should we release this memory? */
1308 MONO_GC_REGISTER_ROOT_FIXED (appdomains_list);
1310 domain = mono_domain_create ();
1311 mono_root_domain = domain;
1313 SET_APPDOMAIN (domain);
1315 /* Get a list of runtimes supported by the exe */
1316 if (exe_filename != NULL) {
1318 * This function will load the exe file as a MonoImage. We need to close it, but
1319 * that would mean it would be reloaded later. So instead, we save it to
1320 * exe_image, and close it during shutdown.
1322 get_runtimes_from_exe (exe_filename, &exe_image, runtimes);
1325 exe_image = mono_assembly_open_from_bundle (exe_filename, NULL, FALSE);
1327 exe_image = mono_image_open (exe_filename, NULL);
1329 mono_fixup_exe_image (exe_image);
1331 } else if (runtime_version != NULL) {
1332 runtimes [0] = get_runtime_by_version (runtime_version);
1333 runtimes [1] = NULL;
1336 if (runtimes [0] == NULL) {
1337 const MonoRuntimeInfo *default_runtime = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
1338 runtimes [0] = default_runtime;
1339 runtimes [1] = NULL;
1340 g_print ("WARNING: The runtime version supported by this application is unavailable.\n");
1341 g_print ("Using default runtime: %s\n", default_runtime->runtime_version);
1344 /* The selected runtime will be the first one for which there is a mscrolib.dll */
1345 for (n = 0; runtimes [n] != NULL && ass == NULL; n++) {
1346 current_runtime = runtimes [n];
1347 ass = mono_assembly_load_corlib (current_runtime, &status);
1348 if (status != MONO_IMAGE_OK && status != MONO_IMAGE_ERROR_ERRNO)
1353 if ((status != MONO_IMAGE_OK) || (ass == NULL)) {
1355 case MONO_IMAGE_ERROR_ERRNO: {
1356 char *corlib_file = g_build_filename (mono_assembly_getrootdir (), "mono", current_runtime->framework_version, "mscorlib.dll", NULL);
1357 g_print ("The assembly mscorlib.dll was not found or could not be loaded.\n");
1358 g_print ("It should have been installed in the `%s' directory.\n", corlib_file);
1359 g_free (corlib_file);
1362 case MONO_IMAGE_IMAGE_INVALID:
1363 g_print ("The file %s/mscorlib.dll is an invalid CIL image\n",
1364 mono_assembly_getrootdir ());
1366 case MONO_IMAGE_MISSING_ASSEMBLYREF:
1367 g_print ("Missing assembly reference in %s/mscorlib.dll\n",
1368 mono_assembly_getrootdir ());
1371 /* to suppress compiler warning */
1377 mono_defaults.corlib = mono_assembly_get_image (ass);
1379 mono_defaults.object_class = mono_class_from_name (
1380 mono_defaults.corlib, "System", "Object");
1381 g_assert (mono_defaults.object_class != 0);
1383 mono_defaults.void_class = mono_class_from_name (
1384 mono_defaults.corlib, "System", "Void");
1385 g_assert (mono_defaults.void_class != 0);
1387 mono_defaults.boolean_class = mono_class_from_name (
1388 mono_defaults.corlib, "System", "Boolean");
1389 g_assert (mono_defaults.boolean_class != 0);
1391 mono_defaults.byte_class = mono_class_from_name (
1392 mono_defaults.corlib, "System", "Byte");
1393 g_assert (mono_defaults.byte_class != 0);
1395 mono_defaults.sbyte_class = mono_class_from_name (
1396 mono_defaults.corlib, "System", "SByte");
1397 g_assert (mono_defaults.sbyte_class != 0);
1399 mono_defaults.int16_class = mono_class_from_name (
1400 mono_defaults.corlib, "System", "Int16");
1401 g_assert (mono_defaults.int16_class != 0);
1403 mono_defaults.uint16_class = mono_class_from_name (
1404 mono_defaults.corlib, "System", "UInt16");
1405 g_assert (mono_defaults.uint16_class != 0);
1407 mono_defaults.int32_class = mono_class_from_name (
1408 mono_defaults.corlib, "System", "Int32");
1409 g_assert (mono_defaults.int32_class != 0);
1411 mono_defaults.uint32_class = mono_class_from_name (
1412 mono_defaults.corlib, "System", "UInt32");
1413 g_assert (mono_defaults.uint32_class != 0);
1415 mono_defaults.uint_class = mono_class_from_name (
1416 mono_defaults.corlib, "System", "UIntPtr");
1417 g_assert (mono_defaults.uint_class != 0);
1419 mono_defaults.int_class = mono_class_from_name (
1420 mono_defaults.corlib, "System", "IntPtr");
1421 g_assert (mono_defaults.int_class != 0);
1423 mono_defaults.int64_class = mono_class_from_name (
1424 mono_defaults.corlib, "System", "Int64");
1425 g_assert (mono_defaults.int64_class != 0);
1427 mono_defaults.uint64_class = mono_class_from_name (
1428 mono_defaults.corlib, "System", "UInt64");
1429 g_assert (mono_defaults.uint64_class != 0);
1431 mono_defaults.single_class = mono_class_from_name (
1432 mono_defaults.corlib, "System", "Single");
1433 g_assert (mono_defaults.single_class != 0);
1435 mono_defaults.double_class = mono_class_from_name (
1436 mono_defaults.corlib, "System", "Double");
1437 g_assert (mono_defaults.double_class != 0);
1439 mono_defaults.char_class = mono_class_from_name (
1440 mono_defaults.corlib, "System", "Char");
1441 g_assert (mono_defaults.char_class != 0);
1443 mono_defaults.string_class = mono_class_from_name (
1444 mono_defaults.corlib, "System", "String");
1445 g_assert (mono_defaults.string_class != 0);
1447 mono_defaults.enum_class = mono_class_from_name (
1448 mono_defaults.corlib, "System", "Enum");
1449 g_assert (mono_defaults.enum_class != 0);
1451 mono_defaults.array_class = mono_class_from_name (
1452 mono_defaults.corlib, "System", "Array");
1453 g_assert (mono_defaults.array_class != 0);
1455 mono_defaults.delegate_class = mono_class_from_name (
1456 mono_defaults.corlib, "System", "Delegate");
1457 g_assert (mono_defaults.delegate_class != 0 );
1459 mono_defaults.multicastdelegate_class = mono_class_from_name (
1460 mono_defaults.corlib, "System", "MulticastDelegate");
1461 g_assert (mono_defaults.multicastdelegate_class != 0 );
1463 mono_defaults.asyncresult_class = mono_class_from_name (
1464 mono_defaults.corlib, "System.Runtime.Remoting.Messaging",
1466 g_assert (mono_defaults.asyncresult_class != 0 );
1468 mono_defaults.manualresetevent_class = mono_class_from_name (
1469 mono_defaults.corlib, "System.Threading", "ManualResetEvent");
1470 g_assert (mono_defaults.manualresetevent_class != 0 );
1472 mono_defaults.typehandle_class = mono_class_from_name (
1473 mono_defaults.corlib, "System", "RuntimeTypeHandle");
1474 g_assert (mono_defaults.typehandle_class != 0);
1476 mono_defaults.methodhandle_class = mono_class_from_name (
1477 mono_defaults.corlib, "System", "RuntimeMethodHandle");
1478 g_assert (mono_defaults.methodhandle_class != 0);
1480 mono_defaults.fieldhandle_class = mono_class_from_name (
1481 mono_defaults.corlib, "System", "RuntimeFieldHandle");
1482 g_assert (mono_defaults.fieldhandle_class != 0);
1484 mono_defaults.systemtype_class = mono_class_from_name (
1485 mono_defaults.corlib, "System", "Type");
1486 g_assert (mono_defaults.systemtype_class != 0);
1488 mono_defaults.monotype_class = mono_class_from_name (
1489 mono_defaults.corlib, "System", "MonoType");
1490 g_assert (mono_defaults.monotype_class != 0);
1492 mono_defaults.exception_class = mono_class_from_name (
1493 mono_defaults.corlib, "System", "Exception");
1494 g_assert (mono_defaults.exception_class != 0);
1496 mono_defaults.threadabortexception_class = mono_class_from_name (
1497 mono_defaults.corlib, "System.Threading", "ThreadAbortException");
1498 g_assert (mono_defaults.threadabortexception_class != 0);
1500 mono_defaults.thread_class = mono_class_from_name (
1501 mono_defaults.corlib, "System.Threading", "Thread");
1502 g_assert (mono_defaults.thread_class != 0);
1504 mono_defaults.internal_thread_class = mono_class_from_name (
1505 mono_defaults.corlib, "System.Threading", "InternalThread");
1506 if (!mono_defaults.internal_thread_class) {
1507 /* This can happen with an old mscorlib */
1508 fprintf (stderr, "Corlib too old for this runtime.\n");
1509 fprintf (stderr, "Loaded from: %s\n",
1510 mono_defaults.corlib? mono_image_get_filename (mono_defaults.corlib): "unknown");
1514 mono_defaults.appdomain_class = mono_class_from_name (
1515 mono_defaults.corlib, "System", "AppDomain");
1516 g_assert (mono_defaults.appdomain_class != 0);
1518 #ifndef DISABLE_REMOTING
1519 mono_defaults.transparent_proxy_class = mono_class_from_name (
1520 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "TransparentProxy");
1521 g_assert (mono_defaults.transparent_proxy_class != 0);
1523 mono_defaults.real_proxy_class = mono_class_from_name (
1524 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "RealProxy");
1525 g_assert (mono_defaults.real_proxy_class != 0);
1527 mono_defaults.marshalbyrefobject_class = mono_class_from_name (
1528 mono_defaults.corlib, "System", "MarshalByRefObject");
1529 g_assert (mono_defaults.marshalbyrefobject_class != 0);
1531 mono_defaults.iremotingtypeinfo_class = mono_class_from_name (
1532 mono_defaults.corlib, "System.Runtime.Remoting", "IRemotingTypeInfo");
1533 g_assert (mono_defaults.iremotingtypeinfo_class != 0);
1536 mono_defaults.mono_method_message_class = mono_class_from_name (
1537 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", "MonoMethodMessage");
1538 g_assert (mono_defaults.mono_method_message_class != 0);
1540 mono_defaults.field_info_class = mono_class_from_name (
1541 mono_defaults.corlib, "System.Reflection", "FieldInfo");
1542 g_assert (mono_defaults.field_info_class != 0);
1544 mono_defaults.method_info_class = mono_class_from_name (
1545 mono_defaults.corlib, "System.Reflection", "MethodInfo");
1546 g_assert (mono_defaults.method_info_class != 0);
1548 mono_defaults.stringbuilder_class = mono_class_from_name (
1549 mono_defaults.corlib, "System.Text", "StringBuilder");
1550 g_assert (mono_defaults.stringbuilder_class != 0);
1552 mono_defaults.math_class = mono_class_from_name (
1553 mono_defaults.corlib, "System", "Math");
1554 g_assert (mono_defaults.math_class != 0);
1556 mono_defaults.stack_frame_class = mono_class_from_name (
1557 mono_defaults.corlib, "System.Diagnostics", "StackFrame");
1558 g_assert (mono_defaults.stack_frame_class != 0);
1560 mono_defaults.stack_trace_class = mono_class_from_name (
1561 mono_defaults.corlib, "System.Diagnostics", "StackTrace");
1562 g_assert (mono_defaults.stack_trace_class != 0);
1564 mono_defaults.marshal_class = mono_class_from_name (
1565 mono_defaults.corlib, "System.Runtime.InteropServices", "Marshal");
1566 g_assert (mono_defaults.marshal_class != 0);
1568 mono_defaults.typed_reference_class = mono_class_from_name (
1569 mono_defaults.corlib, "System", "TypedReference");
1570 g_assert (mono_defaults.typed_reference_class != 0);
1572 mono_defaults.argumenthandle_class = mono_class_from_name (
1573 mono_defaults.corlib, "System", "RuntimeArgumentHandle");
1574 g_assert (mono_defaults.argumenthandle_class != 0);
1576 mono_defaults.monitor_class = mono_class_from_name (
1577 mono_defaults.corlib, "System.Threading", "Monitor");
1578 g_assert (mono_defaults.monitor_class != 0);
1580 mono_defaults.runtimesecurityframe_class = mono_class_from_name (
1581 mono_defaults.corlib, "System.Security", "RuntimeSecurityFrame");
1583 mono_defaults.executioncontext_class = mono_class_from_name (
1584 mono_defaults.corlib, "System.Threading", "ExecutionContext");
1586 mono_defaults.internals_visible_class = mono_class_from_name (
1587 mono_defaults.corlib, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute");
1589 mono_defaults.critical_finalizer_object = mono_class_from_name (
1590 mono_defaults.corlib, "System.Runtime.ConstrainedExecution", "CriticalFinalizerObject");
1593 * mscorlib needs a little help, only now it can load its friends list (after we have
1594 * loaded the InternalsVisibleToAttribute), load it now
1596 mono_assembly_load_friends (ass);
1598 mono_defaults.safehandle_class = mono_class_from_name (
1599 mono_defaults.corlib, "System.Runtime.InteropServices", "SafeHandle");
1601 mono_defaults.handleref_class = mono_class_from_name (
1602 mono_defaults.corlib, "System.Runtime.InteropServices", "HandleRef");
1604 mono_defaults.attribute_class = mono_class_from_name (
1605 mono_defaults.corlib, "System", "Attribute");
1607 mono_defaults.customattribute_data_class = mono_class_from_name (
1608 mono_defaults.corlib, "System.Reflection", "CustomAttributeData");
1610 /* these are initialized lazily when COM features are used */
1612 mono_class_init (mono_defaults.array_class);
1613 mono_defaults.generic_nullable_class = mono_class_from_name (
1614 mono_defaults.corlib, "System", "Nullable`1");
1615 mono_defaults.generic_ilist_class = mono_class_from_name (
1616 mono_defaults.corlib, "System.Collections.Generic", "IList`1");
1617 mono_defaults.generic_ireadonlylist_class = mono_class_from_name (
1618 mono_defaults.corlib, "System.Collections.Generic", "IReadOnlyList`1");
1620 domain->friendly_name = g_path_get_basename (filename);
1622 _mono_debug_init_corlib (domain);
1630 * Creates the initial application domain and initializes the mono_defaults
1632 * This function is guaranteed to not run any IL code.
1633 * The runtime is initialized using the default runtime version.
1635 * Returns: the initial domain.
1638 mono_init (const char *domain_name)
1640 return mono_init_internal (domain_name, NULL, DEFAULT_RUNTIME_VERSION);
1644 * mono_init_from_assembly:
1645 * @domain_name: name to give to the initial domain
1646 * @filename: filename to load on startup
1648 * Used by the runtime, users should use mono_jit_init instead.
1650 * Creates the initial application domain and initializes the mono_defaults
1652 * This function is guaranteed to not run any IL code.
1653 * The runtime is initialized using the runtime version required by the
1654 * provided executable. The version is determined by looking at the exe
1655 * configuration file and the version PE field)
1657 * Returns: the initial domain.
1660 mono_init_from_assembly (const char *domain_name, const char *filename)
1662 return mono_init_internal (domain_name, filename, NULL);
1666 * mono_init_version:
1668 * Used by the runtime, users should use mono_jit_init instead.
1670 * Creates the initial application domain and initializes the mono_defaults
1673 * This function is guaranteed to not run any IL code.
1674 * The runtime is initialized using the provided rutime version.
1676 * Returns: the initial domain.
1679 mono_init_version (const char *domain_name, const char *version)
1681 return mono_init_internal (domain_name, NULL, version);
1687 * Cleans up all metadata modules.
1692 mono_close_exe_image ();
1694 mono_defaults.corlib = NULL;
1696 mono_config_cleanup ();
1697 mono_loader_cleanup ();
1698 mono_classes_cleanup ();
1699 mono_assemblies_cleanup ();
1700 mono_images_cleanup ();
1701 mono_debug_cleanup ();
1702 mono_metadata_cleanup ();
1704 mono_native_tls_free (appdomain_thread_id);
1705 DeleteCriticalSection (&appdomains_mutex);
1713 mono_close_exe_image (void)
1716 mono_image_close (exe_image);
1720 * mono_get_root_domain:
1722 * The root AppDomain is the initial domain created by the runtime when it is
1723 * initialized. Programs execute on this AppDomain, but can create new ones
1724 * later. Currently there is no unmanaged API to create new AppDomains, this
1725 * must be done from managed code.
1727 * Returns: the root appdomain, to obtain the current domain, use mono_domain_get ()
1730 mono_get_root_domain (void)
1732 return mono_root_domain;
1738 * Returns: the current domain, to obtain the root domain use
1739 * mono_get_root_domain().
1744 return GET_APPDOMAIN ();
1748 mono_domain_unset (void)
1750 SET_APPDOMAIN (NULL);
1754 mono_domain_set_internal_with_options (MonoDomain *domain, gboolean migrate_exception)
1756 MonoInternalThread *thread;
1758 if (mono_domain_get () == domain)
1761 SET_APPDOMAIN (domain);
1762 SET_APPCONTEXT (domain->default_context);
1764 if (migrate_exception) {
1765 thread = mono_thread_internal_current ();
1766 if (!thread->abort_exc)
1769 g_assert (thread->abort_exc->object.vtable->domain != domain);
1770 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
1771 g_assert (thread->abort_exc->object.vtable->domain == domain);
1776 * mono_domain_set_internal:
1777 * @domain: the new domain
1779 * Sets the current domain to @domain.
1782 mono_domain_set_internal (MonoDomain *domain)
1784 mono_domain_set_internal_with_options (domain, TRUE);
1788 mono_domain_foreach (MonoDomainFunc func, gpointer user_data)
1794 * Create a copy of the data to avoid calling the user callback
1795 * inside the lock because that could lead to deadlocks.
1796 * We can do this because this function is not perf. critical.
1798 mono_appdomains_lock ();
1799 size = appdomain_list_size;
1800 copy = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1801 memcpy (copy, appdomains_list, appdomain_list_size * sizeof (void*));
1802 mono_appdomains_unlock ();
1804 for (i = 0; i < size; ++i) {
1806 func (copy [i], user_data);
1809 mono_gc_free_fixed (copy);
1813 * mono_domain_assembly_open:
1814 * @domain: the application domain
1815 * @name: file name of the assembly
1817 * fixme: maybe we should integrate this with mono_assembly_open ??
1820 mono_domain_assembly_open (MonoDomain *domain, const char *name)
1822 MonoDomain *current;
1826 mono_domain_assemblies_lock (domain);
1827 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1829 if (strcmp (name, ass->aname.name) == 0) {
1830 mono_domain_assemblies_unlock (domain);
1834 mono_domain_assemblies_unlock (domain);
1836 if (domain != mono_domain_get ()) {
1837 current = mono_domain_get ();
1839 mono_domain_set (domain, FALSE);
1840 ass = mono_assembly_open (name, NULL);
1841 mono_domain_set (current, FALSE);
1843 ass = mono_assembly_open (name, NULL);
1850 unregister_vtable_reflection_type (MonoVTable *vtable)
1852 MonoObject *type = vtable->type;
1854 if (type->vtable->klass != mono_defaults.monotype_class)
1855 MONO_GC_UNREGISTER_ROOT_IF_MOVING (vtable->type);
1859 mono_domain_free (MonoDomain *domain, gboolean force)
1861 int code_size, code_alloc;
1863 if ((domain == mono_root_domain) && !force) {
1864 g_warning ("cant unload root domain");
1868 if (mono_dont_free_domains)
1871 mono_profiler_appdomain_event (domain, MONO_PROFILE_START_UNLOAD);
1873 mono_debug_domain_unload (domain);
1875 mono_appdomains_lock ();
1876 appdomains_list [domain->domain_id] = NULL;
1877 mono_appdomains_unlock ();
1879 /* must do this early as it accesses fields and types */
1880 if (domain->special_static_fields) {
1881 mono_alloc_special_static_data_free (domain->special_static_fields);
1882 g_hash_table_destroy (domain->special_static_fields);
1883 domain->special_static_fields = NULL;
1887 * We must destroy all these hash tables here because they
1888 * contain references to managed objects belonging to the
1889 * domain. Once we let the GC clear the domain there must be
1890 * no more such references, or we'll crash if a collection
1893 mono_g_hash_table_destroy (domain->ldstr_table);
1894 domain->ldstr_table = NULL;
1896 mono_g_hash_table_destroy (domain->env);
1899 if (domain->tlsrec_list) {
1900 mono_thread_destroy_domain_tls (domain);
1901 domain->tlsrec_list = NULL;
1904 mono_reflection_cleanup_domain (domain);
1906 if (domain->type_hash) {
1907 mono_g_hash_table_destroy (domain->type_hash);
1908 domain->type_hash = NULL;
1910 if (domain->type_init_exception_hash) {
1911 mono_g_hash_table_destroy (domain->type_init_exception_hash);
1912 domain->type_init_exception_hash = NULL;
1915 if (domain->class_vtable_array) {
1917 for (i = 0; i < domain->class_vtable_array->len; ++i)
1918 unregister_vtable_reflection_type (g_ptr_array_index (domain->class_vtable_array, i));
1921 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1922 MonoAssembly *ass = tmp->data;
1923 mono_assembly_release_gc_roots (ass);
1926 /* This needs to be done before closing assemblies */
1927 mono_gc_clear_domain (domain);
1929 /* Close dynamic assemblies first, since they have no ref count */
1930 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1931 MonoAssembly *ass = tmp->data;
1932 if (!ass->image || !ass->image->dynamic)
1934 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading domain %s[%p], assembly %s[%p], ref_count=%d", domain->friendly_name, domain, ass->aname.name, ass, ass->ref_count);
1935 if (!mono_assembly_close_except_image_pools (ass))
1939 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1940 MonoAssembly *ass = tmp->data;
1943 if (!ass->image || ass->image->dynamic)
1945 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading domain %s[%p], assembly %s[%p], ref_count=%d", domain->friendly_name, domain, ass->aname.name, ass, ass->ref_count);
1946 if (!mono_assembly_close_except_image_pools (ass))
1950 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1951 MonoAssembly *ass = tmp->data;
1953 mono_assembly_close_finish (ass);
1955 g_slist_free (domain->domain_assemblies);
1956 domain->domain_assemblies = NULL;
1959 * Send this after the assemblies have been unloaded and the domain is still in a
1962 mono_profiler_appdomain_event (domain, MONO_PROFILE_END_UNLOAD);
1964 if (free_domain_hook)
1965 free_domain_hook (domain);
1967 /* FIXME: free delegate_hash_table when it's used */
1968 if (domain->search_path) {
1969 g_strfreev (domain->search_path);
1970 domain->search_path = NULL;
1972 domain->create_proxy_for_type_method = NULL;
1973 domain->private_invoke_method = NULL;
1974 domain->default_context = NULL;
1975 domain->out_of_memory_ex = NULL;
1976 domain->null_reference_ex = NULL;
1977 domain->stack_overflow_ex = NULL;
1978 domain->ephemeron_tombstone = NULL;
1979 domain->entry_assembly = NULL;
1981 g_free (domain->friendly_name);
1982 domain->friendly_name = NULL;
1983 g_ptr_array_free (domain->class_vtable_array, TRUE);
1984 domain->class_vtable_array = NULL;
1985 g_hash_table_destroy (domain->proxy_vtable_hash);
1986 domain->proxy_vtable_hash = NULL;
1987 if (domain->static_data_array) {
1988 mono_gc_free_fixed (domain->static_data_array);
1989 domain->static_data_array = NULL;
1991 mono_internal_hash_table_destroy (&domain->jit_code_hash);
1994 * There might still be jit info tables of this domain which
1995 * are not freed. Since the domain cannot be in use anymore,
1996 * this will free them.
1998 mono_thread_hazardous_try_free_all ();
1999 g_assert (domain->num_jit_info_tables == 1);
2000 jit_info_table_free (domain->jit_info_table);
2001 domain->jit_info_table = NULL;
2002 g_assert (!domain->jit_info_free_queue);
2004 /* collect statistics */
2005 code_alloc = mono_code_manager_size (domain->code_mp, &code_size);
2006 total_domain_code_alloc += code_alloc;
2007 max_domain_code_alloc = MAX (max_domain_code_alloc, code_alloc);
2008 max_domain_code_size = MAX (max_domain_code_size, code_size);
2010 #ifdef DEBUG_DOMAIN_UNLOAD
2011 mono_mempool_invalidate (domain->mp);
2012 mono_code_manager_invalidate (domain->code_mp);
2014 #ifndef DISABLE_PERFCOUNTERS
2015 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 if (domain->method_rgctx_hash) {
2026 g_hash_table_destroy (domain->method_rgctx_hash);
2027 domain->method_rgctx_hash = NULL;
2029 if (domain->generic_virtual_cases) {
2030 g_hash_table_destroy (domain->generic_virtual_cases);
2031 domain->generic_virtual_cases = NULL;
2033 if (domain->generic_virtual_thunks) {
2034 g_hash_table_destroy (domain->generic_virtual_thunks);
2035 domain->generic_virtual_thunks = NULL;
2037 if (domain->ftnptrs_hash) {
2038 g_hash_table_destroy (domain->ftnptrs_hash);
2039 domain->ftnptrs_hash = 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 #ifndef DISABLE_PERFCOUNTERS
2055 mono_perfcounters->loader_appdomains--;
2058 if (domain == mono_root_domain)
2059 mono_root_domain = NULL;
2063 * mono_domain_get_id:
2066 * Returns: the a domain for a specific domain id.
2069 mono_domain_get_by_id (gint32 domainid)
2071 MonoDomain * domain;
2073 mono_appdomains_lock ();
2074 if (domainid < appdomain_list_size)
2075 domain = appdomains_list [domainid];
2078 mono_appdomains_unlock ();
2084 mono_domain_get_id (MonoDomain *domain)
2086 return domain->domain_id;
2090 * mono_domain_alloc:
2092 * LOCKING: Acquires the domain lock.
2095 mono_domain_alloc (MonoDomain *domain, guint size)
2099 mono_domain_lock (domain);
2100 #ifndef DISABLE_PERFCOUNTERS
2101 mono_perfcounters->loader_bytes += size;
2103 res = mono_mempool_alloc (domain->mp, size);
2104 mono_domain_unlock (domain);
2110 * mono_domain_alloc0:
2112 * LOCKING: Acquires the domain lock.
2115 mono_domain_alloc0 (MonoDomain *domain, guint size)
2119 mono_domain_lock (domain);
2120 #ifndef DISABLE_PERFCOUNTERS
2121 mono_perfcounters->loader_bytes += size;
2123 res = mono_mempool_alloc0 (domain->mp, size);
2124 mono_domain_unlock (domain);
2130 * mono_domain_code_reserve:
2132 * LOCKING: Acquires the domain lock.
2135 mono_domain_code_reserve (MonoDomain *domain, int size)
2139 mono_domain_lock (domain);
2140 res = mono_code_manager_reserve (domain->code_mp, size);
2141 mono_domain_unlock (domain);
2147 * mono_domain_code_reserve_align:
2149 * LOCKING: Acquires the domain lock.
2152 mono_domain_code_reserve_align (MonoDomain *domain, int size, int alignment)
2156 mono_domain_lock (domain);
2157 res = mono_code_manager_reserve_align (domain->code_mp, size, alignment);
2158 mono_domain_unlock (domain);
2164 * mono_domain_code_commit:
2166 * LOCKING: Acquires the domain lock.
2169 mono_domain_code_commit (MonoDomain *domain, void *data, int size, int newsize)
2171 mono_domain_lock (domain);
2172 mono_code_manager_commit (domain->code_mp, data, size, newsize);
2173 mono_domain_unlock (domain);
2176 #if defined(__native_client_codegen__) && defined(__native_client__)
2178 * Given the temporary buffer (allocated by mono_domain_code_reserve) into which
2179 * we are generating code, return a pointer to the destination in the dynamic
2180 * code segment into which the code will be copied when mono_domain_code_commit
2182 * LOCKING: Acquires the domain lock.
2185 nacl_domain_get_code_dest (MonoDomain *domain, void *data)
2188 mono_domain_lock (domain);
2189 dest = nacl_code_manager_get_code_dest (domain->code_mp, data);
2190 mono_domain_unlock (domain);
2195 * Convenience function which calls mono_domain_code_commit to validate and copy
2196 * the code. The caller sets *buf_base and *buf_size to the start and size of
2197 * the buffer (allocated by mono_domain_code_reserve), and *code_end to the byte
2198 * after the last instruction byte. On return, *buf_base will point to the start
2199 * of the copied in the code segment, and *code_end will point after the end of
2203 nacl_domain_code_validate (MonoDomain *domain, guint8 **buf_base, int buf_size, guint8 **code_end)
2205 guint8 *tmp = nacl_domain_get_code_dest (domain, *buf_base);
2206 mono_domain_code_commit (domain, *buf_base, buf_size, *code_end - *buf_base);
2207 *code_end = tmp + (*code_end - *buf_base);
2213 /* no-op versions of Native Client functions */
2216 nacl_domain_get_code_dest (MonoDomain *domain, void *data)
2222 nacl_domain_code_validate (MonoDomain *domain, guint8 **buf_base, int buf_size, guint8 **code_end)
2229 * mono_domain_code_foreach:
2230 * Iterate over the code thunks of the code manager of @domain.
2232 * The @func callback MUST not take any locks. If it really needs to, it must respect
2233 * the locking rules of the runtime: http://www.mono-project.com/Mono:Runtime:Documentation:ThreadSafety
2234 * LOCKING: Acquires the domain lock.
2238 mono_domain_code_foreach (MonoDomain *domain, MonoCodeManagerFunc func, void *user_data)
2240 mono_domain_lock (domain);
2241 mono_code_manager_foreach (domain->code_mp, func, user_data);
2242 mono_domain_unlock (domain);
2247 mono_context_set (MonoAppContext * new_context)
2249 SET_APPCONTEXT (new_context);
2253 mono_context_get (void)
2255 return GET_APPCONTEXT ();
2258 /* LOCKING: the caller holds the lock for this domain */
2260 mono_domain_add_class_static_data (MonoDomain *domain, MonoClass *klass, gpointer data, guint32 *bitmap)
2262 /* The first entry in the array is the index of the next free slot
2263 * and the total size of the array
2266 if (domain->static_data_array) {
2267 int size = GPOINTER_TO_INT (domain->static_data_array [1]);
2268 next = GPOINTER_TO_INT (domain->static_data_array [0]);
2270 /* 'data' is allocated by alloc_fixed */
2271 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * (size * 2), MONO_GC_ROOT_DESCR_FOR_FIXED (size * 2));
2272 mono_gc_memmove (new_array, domain->static_data_array, sizeof (gpointer) * size);
2274 new_array [1] = GINT_TO_POINTER (size);
2275 mono_gc_free_fixed (domain->static_data_array);
2276 domain->static_data_array = new_array;
2280 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * size, MONO_GC_ROOT_DESCR_FOR_FIXED (size));
2282 new_array [0] = GINT_TO_POINTER (next);
2283 new_array [1] = GINT_TO_POINTER (size);
2284 domain->static_data_array = new_array;
2286 domain->static_data_array [next++] = data;
2287 domain->static_data_array [0] = GINT_TO_POINTER (next);
2291 mono_get_corlib (void)
2293 return mono_defaults.corlib;
2297 mono_get_object_class (void)
2299 return mono_defaults.object_class;
2303 mono_get_byte_class (void)
2305 return mono_defaults.byte_class;
2309 mono_get_void_class (void)
2311 return mono_defaults.void_class;
2315 mono_get_boolean_class (void)
2317 return mono_defaults.boolean_class;
2321 mono_get_sbyte_class (void)
2323 return mono_defaults.sbyte_class;
2327 mono_get_int16_class (void)
2329 return mono_defaults.int16_class;
2333 mono_get_uint16_class (void)
2335 return mono_defaults.uint16_class;
2339 mono_get_int32_class (void)
2341 return mono_defaults.int32_class;
2345 mono_get_uint32_class (void)
2347 return mono_defaults.uint32_class;
2351 mono_get_intptr_class (void)
2353 return mono_defaults.int_class;
2357 mono_get_uintptr_class (void)
2359 return mono_defaults.uint_class;
2363 mono_get_int64_class (void)
2365 return mono_defaults.int64_class;
2369 mono_get_uint64_class (void)
2371 return mono_defaults.uint64_class;
2375 mono_get_single_class (void)
2377 return mono_defaults.single_class;
2381 mono_get_double_class (void)
2383 return mono_defaults.double_class;
2387 mono_get_char_class (void)
2389 return mono_defaults.char_class;
2393 mono_get_string_class (void)
2395 return mono_defaults.string_class;
2399 mono_get_enum_class (void)
2401 return mono_defaults.enum_class;
2405 mono_get_array_class (void)
2407 return mono_defaults.array_class;
2411 mono_get_thread_class (void)
2413 return mono_defaults.thread_class;
2417 mono_get_exception_class (void)
2419 return mono_defaults.exception_class;
2423 static char* get_attribute_value (const gchar **attribute_names,
2424 const gchar **attribute_values,
2425 const char *att_name)
2428 for (n=0; attribute_names[n] != NULL; n++) {
2429 if (strcmp (attribute_names[n], att_name) == 0)
2430 return g_strdup (attribute_values[n]);
2435 static void start_element (GMarkupParseContext *context,
2436 const gchar *element_name,
2437 const gchar **attribute_names,
2438 const gchar **attribute_values,
2442 AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2444 if (strcmp (element_name, "configuration") == 0) {
2445 app_config->configuration_count++;
2448 if (strcmp (element_name, "startup") == 0) {
2449 app_config->startup_count++;
2453 if (app_config->configuration_count != 1 || app_config->startup_count != 1)
2456 if (strcmp (element_name, "requiredRuntime") == 0) {
2457 app_config->required_runtime = get_attribute_value (attribute_names, attribute_values, "version");
2458 } else if (strcmp (element_name, "supportedRuntime") == 0) {
2459 char *version = get_attribute_value (attribute_names, attribute_values, "version");
2460 app_config->supported_runtimes = g_slist_append (app_config->supported_runtimes, version);
2464 static void end_element (GMarkupParseContext *context,
2465 const gchar *element_name,
2469 AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2471 if (strcmp (element_name, "configuration") == 0) {
2472 app_config->configuration_count--;
2473 } else if (strcmp (element_name, "startup") == 0) {
2474 app_config->startup_count--;
2478 static const GMarkupParser
2487 static AppConfigInfo *
2488 app_config_parse (const char *exe_filename)
2490 AppConfigInfo *app_config;
2491 GMarkupParseContext *context;
2494 const char *bundled_config;
2495 char *config_filename;
2497 bundled_config = mono_config_string_for_assembly_file (exe_filename);
2499 if (bundled_config) {
2500 text = g_strdup (bundled_config);
2501 len = strlen (text);
2503 config_filename = g_strconcat (exe_filename, ".config", NULL);
2505 if (!g_file_get_contents (config_filename, &text, &len, NULL)) {
2506 g_free (config_filename);
2509 g_free (config_filename);
2512 app_config = g_new0 (AppConfigInfo, 1);
2514 context = g_markup_parse_context_new (&mono_parser, 0, app_config, NULL);
2515 if (g_markup_parse_context_parse (context, text, len, NULL)) {
2516 g_markup_parse_context_end_parse (context, NULL);
2518 g_markup_parse_context_free (context);
2524 app_config_free (AppConfigInfo* app_config)
2527 GSList *list = app_config->supported_runtimes;
2528 while (list != NULL) {
2529 rt = (char*)list->data;
2531 list = g_slist_next (list);
2533 g_slist_free (app_config->supported_runtimes);
2534 g_free (app_config->required_runtime);
2535 g_free (app_config);
2539 static const MonoRuntimeInfo*
2540 get_runtime_by_version (const char *version)
2543 int max = G_N_ELEMENTS (supported_runtimes);
2549 for (n=0; n<max; n++) {
2550 if (strcmp (version, supported_runtimes[n].runtime_version) == 0)
2551 return &supported_runtimes[n];
2554 vlen = strlen (version);
2555 if (vlen >= 4 && version [1] - '0' >= 4) {
2556 for (n=0; n<max; n++) {
2557 if (strncmp (version, supported_runtimes[n].runtime_version, 4) == 0)
2558 return &supported_runtimes[n];
2566 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes)
2568 AppConfigInfo* app_config;
2570 const MonoRuntimeInfo* runtime = NULL;
2571 MonoImage *image = NULL;
2573 app_config = app_config_parse (exe_file);
2575 if (app_config != NULL) {
2576 /* Check supportedRuntime elements, if none is supported, fail.
2577 * If there are no such elements, look for a requiredRuntime element.
2579 if (app_config->supported_runtimes != NULL) {
2581 GSList *list = app_config->supported_runtimes;
2582 while (list != NULL) {
2583 version = (char*) list->data;
2584 runtime = get_runtime_by_version (version);
2585 if (runtime != NULL)
2586 runtimes [n++] = runtime;
2587 list = g_slist_next (list);
2589 runtimes [n] = NULL;
2590 app_config_free (app_config);
2594 /* Check the requiredRuntime element. This is for 1.0 apps only. */
2595 if (app_config->required_runtime != NULL) {
2596 runtimes [0] = get_runtime_by_version (app_config->required_runtime);
2597 runtimes [1] = NULL;
2598 app_config_free (app_config);
2601 app_config_free (app_config);
2604 /* Look for a runtime with the exact version */
2605 image = mono_assembly_open_from_bundle (exe_file, NULL, FALSE);
2608 image = mono_image_open (exe_file, NULL);
2610 if (image == NULL) {
2611 /* The image is wrong or the file was not found. In this case return
2612 * a default runtime and leave to the initialization method the work of
2613 * reporting the error.
2615 runtimes [0] = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
2616 runtimes [1] = NULL;
2622 runtimes [0] = get_runtime_by_version (image->version);
2623 runtimes [1] = NULL;
2628 * mono_get_runtime_info:
2630 * Returns: the version of the current runtime instance.
2632 const MonoRuntimeInfo*
2633 mono_get_runtime_info (void)
2635 return current_runtime;
2639 mono_debugger_check_runtime_version (const char *filename)
2641 const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
2642 const MonoRuntimeInfo *rinfo;
2645 get_runtimes_from_exe (filename, &image, runtimes);
2646 rinfo = runtimes [0];
2649 return g_strdup_printf ("Cannot get runtime version from assembly `%s'", filename);
2651 if (rinfo != current_runtime)
2652 return g_strdup_printf ("The Mono Debugger is currently using the `%s' runtime, but "
2653 "the assembly `%s' requires version `%s'", current_runtime->runtime_version,
2654 filename, rinfo->runtime_version);
2660 * mono_framework_version:
2662 * Return the major version of the framework curently executing.
2665 mono_framework_version (void)
2667 return current_runtime->framework_version [0] - '0';