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.20506","4.0", { {4,0,0,0}, {10,0,0,0}, { 4, 0, 0, 0 } } },
134 {"v4.0.30128","4.0", { {4,0,0,0}, {10,0,0,0}, { 4, 0, 0, 0 } } },
135 {"v4.0.30319","4.0", { {4,0,0,0}, {10,0,0,0}, { 4, 0, 0, 0 } } },
136 {"moonlight", "2.1", { {2,0,5,0}, {9,0,0,0}, { 3, 5, 0, 0 } } },
140 /* The stable runtime version */
141 #define DEFAULT_RUNTIME_VERSION "v2.0.50727"
143 /* Callbacks installed by the JIT */
144 static MonoCreateDomainFunc create_domain_hook;
145 static MonoFreeDomainFunc free_domain_hook;
147 /* This is intentionally not in the header file, so people don't misuse it. */
148 extern void _mono_debug_init_corlib (MonoDomain *domain);
151 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes);
153 static const MonoRuntimeInfo*
154 get_runtime_by_version (const char *version);
157 mono_jit_info_find_aot_module (guint8* addr);
160 mono_domain_get_tls_key (void)
162 return appdomain_thread_id;
166 mono_domain_get_tls_offset (void)
169 MONO_THREAD_VAR_OFFSET (tls_appdomain, offset);
170 /* __asm ("jmp 1f; .section writetext, \"awx\"; 1: movl $tls_appdomain@ntpoff, %0; jmp 2f; .previous; 2:"
175 #define JIT_INFO_TABLE_FILL_RATIO_NOM 3
176 #define JIT_INFO_TABLE_FILL_RATIO_DENOM 4
177 #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)
179 #define JIT_INFO_TABLE_LOW_WATERMARK(n) ((n) / 2)
180 #define JIT_INFO_TABLE_HIGH_WATERMARK(n) ((n) * 5 / 6)
182 #define JIT_INFO_TOMBSTONE_MARKER ((MonoMethod*)NULL)
183 #define IS_JIT_INFO_TOMBSTONE(ji) ((ji)->method == JIT_INFO_TOMBSTONE_MARKER)
185 #define JIT_INFO_TABLE_HAZARD_INDEX 0
186 #define JIT_INFO_HAZARD_INDEX 1
189 jit_info_table_num_elements (MonoJitInfoTable *table)
192 int num_elements = 0;
194 for (i = 0; i < table->num_chunks; ++i) {
195 MonoJitInfoTableChunk *chunk = table->chunks [i];
196 int chunk_num_elements = chunk->num_elements;
199 for (j = 0; j < chunk_num_elements; ++j) {
200 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j]))
208 static MonoJitInfoTableChunk*
209 jit_info_table_new_chunk (void)
211 MonoJitInfoTableChunk *chunk = g_new0 (MonoJitInfoTableChunk, 1);
217 static MonoJitInfoTable *
218 jit_info_table_new (MonoDomain *domain)
220 MonoJitInfoTable *table = g_malloc0 (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*));
222 table->domain = domain;
223 table->num_chunks = 1;
224 table->chunks [0] = jit_info_table_new_chunk ();
230 jit_info_table_free (MonoJitInfoTable *table)
233 int num_chunks = table->num_chunks;
234 MonoDomain *domain = table->domain;
236 mono_domain_lock (domain);
238 table->domain->num_jit_info_tables--;
239 if (table->domain->num_jit_info_tables <= 1) {
242 for (list = table->domain->jit_info_free_queue; list; list = list->next)
245 g_slist_free (table->domain->jit_info_free_queue);
246 table->domain->jit_info_free_queue = NULL;
249 /* At this point we assume that there are no other threads
250 still accessing the table, so we don't have to worry about
251 hazardous pointers. */
253 for (i = 0; i < num_chunks; ++i) {
254 MonoJitInfoTableChunk *chunk = table->chunks [i];
258 if (--chunk->refcount > 0)
261 num_elements = chunk->num_elements;
262 for (j = 0; j < num_elements; ++j) {
263 MonoJitInfo *ji = chunk->data [j];
265 if (IS_JIT_INFO_TOMBSTONE (ji))
272 mono_domain_unlock (domain);
277 /* Can be called with hp==NULL, in which case it acts as an ordinary
278 pointer fetch. It's used that way indirectly from
279 mono_jit_info_table_add(), which doesn't have to care about hazards
280 because it holds the respective domain lock. */
282 get_hazardous_pointer (gpointer volatile *pp, MonoThreadHazardPointers *hp, int hazard_index)
287 /* Get the pointer */
289 /* If we don't have hazard pointers just return the
293 /* Make it hazardous */
294 mono_hazard_pointer_set (hp, hazard_index, p);
295 /* Check that it's still the same. If not, try
298 mono_hazard_pointer_clear (hp, hazard_index);
307 /* The jit_info_table is sorted in ascending order by the end
308 * addresses of the compiled methods. The reason why we have to do
309 * this is that once we introduce tombstones, it becomes possible for
310 * code ranges to overlap, and if we sort by code start and insert at
311 * the back of the table, we cannot guarantee that we won't overlook
314 * There are actually two possible ways to do the sorting and
315 * inserting which work with our lock-free mechanism:
317 * 1. Sort by start address and insert at the front. When looking for
318 * an entry, find the last one with a start address lower than the one
319 * you're looking for, then work your way to the front of the table.
321 * 2. Sort by end address and insert at the back. When looking for an
322 * entry, find the first one with an end address higher than the one
323 * you're looking for, then work your way to the end of the table.
325 * We chose the latter out of convenience.
328 jit_info_table_index (MonoJitInfoTable *table, gint8 *addr)
330 int left = 0, right = table->num_chunks;
332 g_assert (left < right);
335 int pos = (left + right) / 2;
336 MonoJitInfoTableChunk *chunk = table->chunks [pos];
338 if (addr < chunk->last_code_end)
342 } while (left < right);
343 g_assert (left == right);
345 if (left >= table->num_chunks)
346 return table->num_chunks - 1;
351 jit_info_table_chunk_index (MonoJitInfoTableChunk *chunk, MonoThreadHazardPointers *hp, gint8 *addr)
353 int left = 0, right = chunk->num_elements;
355 while (left < right) {
356 int pos = (left + right) / 2;
357 MonoJitInfo *ji = get_hazardous_pointer((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
358 gint8 *code_end = (gint8*)ji->code_start + ji->code_size;
365 g_assert (left == right);
371 mono_jit_info_table_find (MonoDomain *domain, char *addr)
373 MonoJitInfoTable *table;
376 MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
379 ++mono_stats.jit_info_table_lookup_count;
381 /* First we have to get the domain's jit_info_table. This is
382 complicated by the fact that a writer might substitute a
383 new table and free the old one. What the writer guarantees
384 us is that it looks at the hazard pointers after it has
385 changed the jit_info_table pointer. So, if we guard the
386 table by a hazard pointer and make sure that the pointer is
387 still there after we've made it hazardous, we don't have to
388 worry about the writer freeing the table. */
389 table = get_hazardous_pointer ((gpointer volatile*)&domain->jit_info_table, hp, JIT_INFO_TABLE_HAZARD_INDEX);
391 chunk_pos = jit_info_table_index (table, (gint8*)addr);
392 g_assert (chunk_pos < table->num_chunks);
394 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], hp, (gint8*)addr);
396 /* We now have a position that's very close to that of the
397 first element whose end address is higher than the one
398 we're looking for. If we don't have the exact position,
399 then we have a position below that one, so we'll just
400 search upward until we find our element. */
402 MonoJitInfoTableChunk *chunk = table->chunks [chunk_pos];
404 while (pos < chunk->num_elements) {
405 ji = get_hazardous_pointer ((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
409 if (IS_JIT_INFO_TOMBSTONE (ji)) {
410 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
413 if ((gint8*)addr >= (gint8*)ji->code_start
414 && (gint8*)addr < (gint8*)ji->code_start + ji->code_size) {
415 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
416 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
420 /* If we find a non-tombstone element which is already
421 beyond what we're looking for, we have to end the
423 if ((gint8*)addr < (gint8*)ji->code_start)
429 } while (chunk_pos < table->num_chunks);
435 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
436 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
440 /* Maybe its an AOT module */
441 image = mono_jit_info_find_aot_module ((guint8*)addr);
443 ji = jit_info_find_in_aot_func (domain, image, addr);
448 static G_GNUC_UNUSED void
449 jit_info_table_check (MonoJitInfoTable *table)
453 for (i = 0; i < table->num_chunks; ++i) {
454 MonoJitInfoTableChunk *chunk = table->chunks [i];
457 g_assert (chunk->refcount > 0 /* && chunk->refcount <= 8 */);
458 if (chunk->refcount > 10)
459 printf("warning: chunk refcount is %d\n", chunk->refcount);
460 g_assert (chunk->num_elements <= MONO_JIT_INFO_TABLE_CHUNK_SIZE);
462 for (j = 0; j < chunk->num_elements; ++j) {
463 MonoJitInfo *this = chunk->data [j];
466 g_assert ((gint8*)this->code_start + this->code_size <= chunk->last_code_end);
468 if (j < chunk->num_elements - 1)
469 next = chunk->data [j + 1];
470 else if (i < table->num_chunks - 1) {
473 for (k = i + 1; k < table->num_chunks; ++k)
474 if (table->chunks [k]->num_elements > 0)
477 if (k >= table->num_chunks)
480 g_assert (table->chunks [k]->num_elements > 0);
481 next = table->chunks [k]->data [0];
485 g_assert ((gint8*)this->code_start + this->code_size <= (gint8*)next->code_start + next->code_size);
490 static MonoJitInfoTable*
491 jit_info_table_realloc (MonoJitInfoTable *old)
494 int num_elements = jit_info_table_num_elements (old);
497 int new_chunk, new_element;
498 MonoJitInfoTable *new;
500 /* number of needed places for elements needed */
501 required_size = (int)((long)num_elements * JIT_INFO_TABLE_FILL_RATIO_DENOM / JIT_INFO_TABLE_FILL_RATIO_NOM);
502 num_chunks = (required_size + MONO_JIT_INFO_TABLE_CHUNK_SIZE - 1) / MONO_JIT_INFO_TABLE_CHUNK_SIZE;
504 new = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*) * num_chunks);
505 new->domain = old->domain;
506 new->num_chunks = num_chunks;
508 for (i = 0; i < num_chunks; ++i)
509 new->chunks [i] = jit_info_table_new_chunk ();
513 for (i = 0; i < old->num_chunks; ++i) {
514 MonoJitInfoTableChunk *chunk = old->chunks [i];
515 int chunk_num_elements = chunk->num_elements;
518 for (j = 0; j < chunk_num_elements; ++j) {
519 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j])) {
520 g_assert (new_chunk < num_chunks);
521 new->chunks [new_chunk]->data [new_element] = chunk->data [j];
522 if (++new_element >= JIT_INFO_TABLE_FILLED_NUM_ELEMENTS) {
523 new->chunks [new_chunk]->num_elements = new_element;
531 if (new_chunk < num_chunks) {
532 g_assert (new_chunk == num_chunks - 1);
533 new->chunks [new_chunk]->num_elements = new_element;
534 g_assert (new->chunks [new_chunk]->num_elements > 0);
537 for (i = 0; i < num_chunks; ++i) {
538 MonoJitInfoTableChunk *chunk = new->chunks [i];
539 MonoJitInfo *ji = chunk->data [chunk->num_elements - 1];
541 new->chunks [i]->last_code_end = (gint8*)ji->code_start + ji->code_size;
548 jit_info_table_split_chunk (MonoJitInfoTableChunk *chunk, MonoJitInfoTableChunk **new1p, MonoJitInfoTableChunk **new2p)
550 MonoJitInfoTableChunk *new1 = jit_info_table_new_chunk ();
551 MonoJitInfoTableChunk *new2 = jit_info_table_new_chunk ();
553 g_assert (chunk->num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE);
555 new1->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE / 2;
556 new2->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE - new1->num_elements;
558 memcpy ((void*)new1->data, (void*)chunk->data, sizeof (MonoJitInfo*) * new1->num_elements);
559 memcpy ((void*)new2->data, (void*)(chunk->data + new1->num_elements), sizeof (MonoJitInfo*) * new2->num_elements);
561 new1->last_code_end = (gint8*)new1->data [new1->num_elements - 1]->code_start
562 + new1->data [new1->num_elements - 1]->code_size;
563 new2->last_code_end = (gint8*)new2->data [new2->num_elements - 1]->code_start
564 + new2->data [new2->num_elements - 1]->code_size;
570 static MonoJitInfoTable*
571 jit_info_table_copy_and_split_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
573 MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
574 + sizeof (MonoJitInfoTableChunk*) * (table->num_chunks + 1));
577 new_table->domain = table->domain;
578 new_table->num_chunks = table->num_chunks + 1;
581 for (i = 0; i < table->num_chunks; ++i) {
582 if (table->chunks [i] == chunk) {
583 jit_info_table_split_chunk (chunk, &new_table->chunks [j], &new_table->chunks [j + 1]);
586 new_table->chunks [j] = table->chunks [i];
587 ++new_table->chunks [j]->refcount;
592 g_assert (j == new_table->num_chunks);
597 static MonoJitInfoTableChunk*
598 jit_info_table_purify_chunk (MonoJitInfoTableChunk *old)
600 MonoJitInfoTableChunk *new = jit_info_table_new_chunk ();
604 for (i = 0; i < old->num_elements; ++i) {
605 if (!IS_JIT_INFO_TOMBSTONE (old->data [i]))
606 new->data [j++] = old->data [i];
609 new->num_elements = j;
610 if (new->num_elements > 0)
611 new->last_code_end = (gint8*)new->data [j - 1]->code_start + new->data [j - 1]->code_size;
613 new->last_code_end = old->last_code_end;
618 static MonoJitInfoTable*
619 jit_info_table_copy_and_purify_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
621 MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
622 + sizeof (MonoJitInfoTableChunk*) * table->num_chunks);
625 new_table->domain = table->domain;
626 new_table->num_chunks = table->num_chunks;
629 for (i = 0; i < table->num_chunks; ++i) {
630 if (table->chunks [i] == chunk)
631 new_table->chunks [j++] = jit_info_table_purify_chunk (table->chunks [i]);
633 new_table->chunks [j] = table->chunks [i];
634 ++new_table->chunks [j]->refcount;
639 g_assert (j == new_table->num_chunks);
644 /* As we add an element to the table the case can arise that the chunk
645 * to which we need to add is already full. In that case we have to
646 * allocate a new table and do something about that chunk. We have
647 * several strategies:
649 * If the number of elements in the table is below the low watermark
650 * or above the high watermark, we reallocate the whole table.
651 * Otherwise we only concern ourselves with the overflowing chunk:
653 * If there are no tombstones in the chunk then we split the chunk in
654 * two, each half full.
656 * If the chunk does contain tombstones, we just make a new copy of
657 * the chunk without the tombstones, which will have room for at least
658 * the one element we have to add.
660 static MonoJitInfoTable*
661 jit_info_table_chunk_overflow (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
663 int num_elements = jit_info_table_num_elements (table);
666 if (num_elements < JIT_INFO_TABLE_LOW_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)
667 || num_elements > JIT_INFO_TABLE_HIGH_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)) {
668 //printf ("reallocing table\n");
669 return jit_info_table_realloc (table);
672 /* count the number of non-tombstone elements in the chunk */
674 for (i = 0; i < chunk->num_elements; ++i) {
675 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [i]))
679 if (num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
680 //printf ("splitting chunk\n");
681 return jit_info_table_copy_and_split_chunk (table, chunk);
684 //printf ("purifying chunk\n");
685 return jit_info_table_copy_and_purify_chunk (table, chunk);
688 /* We add elements to the table by first making space for them by
689 * shifting the elements at the back to the right, one at a time.
690 * This results in duplicate entries during the process, but during
691 * all the time the table is in a sorted state. Also, when an element
692 * is replaced by another one, the element that replaces it has an end
693 * address that is equal to or lower than that of the replaced
694 * element. That property is necessary to guarantee that when
695 * searching for an element we end up at a position not higher than
696 * the one we're looking for (i.e. we either find the element directly
697 * or we end up to the left of it).
700 mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
702 MonoJitInfoTable *table;
704 MonoJitInfoTableChunk *chunk;
708 g_assert (ji->method != NULL);
710 mono_domain_lock (domain);
712 ++mono_stats.jit_info_table_insert_count;
714 table = domain->jit_info_table;
717 chunk_pos = jit_info_table_index (table, (gint8*)ji->code_start + ji->code_size);
718 g_assert (chunk_pos < table->num_chunks);
719 chunk = table->chunks [chunk_pos];
721 if (chunk->num_elements >= MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
722 MonoJitInfoTable *new_table = jit_info_table_chunk_overflow (table, chunk);
724 /* Debugging code, should be removed. */
725 //jit_info_table_check (new_table);
727 domain->jit_info_table = new_table;
728 mono_memory_barrier ();
729 domain->num_jit_info_tables++;
730 mono_thread_hazardous_free_or_queue (table, (MonoHazardousFreeFunc)jit_info_table_free);
736 /* Debugging code, should be removed. */
737 //jit_info_table_check (table);
739 num_elements = chunk->num_elements;
741 pos = jit_info_table_chunk_index (chunk, NULL, (gint8*)ji->code_start + ji->code_size);
743 /* First we need to size up the chunk by one, by copying the
744 last item, or inserting the first one, if the table is
746 if (num_elements > 0)
747 chunk->data [num_elements] = chunk->data [num_elements - 1];
749 chunk->data [0] = ji;
750 mono_memory_write_barrier ();
751 chunk->num_elements = ++num_elements;
753 /* Shift the elements up one by one. */
754 for (i = num_elements - 2; i >= pos; --i) {
755 mono_memory_write_barrier ();
756 chunk->data [i + 1] = chunk->data [i];
759 /* Now we have room and can insert the new item. */
760 mono_memory_write_barrier ();
761 chunk->data [pos] = ji;
763 /* Set the high code end address chunk entry. */
764 chunk->last_code_end = (gint8*)chunk->data [chunk->num_elements - 1]->code_start
765 + chunk->data [chunk->num_elements - 1]->code_size;
767 /* Debugging code, should be removed. */
768 //jit_info_table_check (table);
770 mono_domain_unlock (domain);
774 mono_jit_info_make_tombstone (MonoJitInfo *ji)
776 MonoJitInfo *tombstone = g_new0 (MonoJitInfo, 1);
778 tombstone->code_start = ji->code_start;
779 tombstone->code_size = ji->code_size;
780 tombstone->method = JIT_INFO_TOMBSTONE_MARKER;
786 * LOCKING: domain lock
789 mono_jit_info_free_or_queue (MonoDomain *domain, MonoJitInfo *ji)
791 if (domain->num_jit_info_tables <= 1) {
792 /* Can it actually happen that we only have one table
793 but ji is still hazardous? */
794 mono_thread_hazardous_free_or_queue (ji, g_free);
796 domain->jit_info_free_queue = g_slist_prepend (domain->jit_info_free_queue, ji);
801 mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
803 MonoJitInfoTable *table;
804 MonoJitInfoTableChunk *chunk;
805 gpointer start = ji->code_start;
808 mono_domain_lock (domain);
809 table = domain->jit_info_table;
811 ++mono_stats.jit_info_table_remove_count;
813 chunk_pos = jit_info_table_index (table, start);
814 g_assert (chunk_pos < table->num_chunks);
816 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], NULL, start);
819 chunk = table->chunks [chunk_pos];
821 while (pos < chunk->num_elements) {
822 if (chunk->data [pos] == ji)
825 g_assert (IS_JIT_INFO_TOMBSTONE (chunk->data [pos]));
826 g_assert ((guint8*)chunk->data [pos]->code_start + chunk->data [pos]->code_size
827 <= (guint8*)ji->code_start + ji->code_size);
834 } while (chunk_pos < table->num_chunks);
837 g_assert (chunk->data [pos] == ji);
839 chunk->data [pos] = mono_jit_info_make_tombstone (ji);
841 /* Debugging code, should be removed. */
842 //jit_info_table_check (table);
844 mono_jit_info_free_or_queue (domain, ji);
846 mono_domain_unlock (domain);
849 static MonoAotModuleInfoTable*
850 mono_aot_module_info_table_new (void)
852 return g_array_new (FALSE, FALSE, sizeof (gpointer));
856 aot_info_table_index (MonoAotModuleInfoTable *table, char *addr)
858 int left = 0, right = table->len;
860 while (left < right) {
861 int pos = (left + right) / 2;
862 AotModuleInfo *ainfo = g_array_index (table, gpointer, pos);
863 char *start = ainfo->start;
864 char *end = ainfo->end;
868 else if (addr >= end)
878 mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
880 AotModuleInfo *ainfo = g_new0 (AotModuleInfo, 1);
883 ainfo->image = image;
884 ainfo->start = start;
887 mono_appdomains_lock ();
890 aot_modules = mono_aot_module_info_table_new ();
892 pos = aot_info_table_index (aot_modules, start);
894 g_array_insert_val (aot_modules, pos, ainfo);
896 mono_appdomains_unlock ();
900 mono_jit_info_find_aot_module (guint8* addr)
902 guint left = 0, right;
907 mono_appdomains_lock ();
909 right = aot_modules->len;
910 while (left < right) {
911 guint pos = (left + right) / 2;
912 AotModuleInfo *ai = g_array_index (aot_modules, gpointer, pos);
914 if (addr < (guint8*)ai->start)
916 else if (addr >= (guint8*)ai->end)
919 mono_appdomains_unlock ();
924 mono_appdomains_unlock ();
930 mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func)
932 jit_info_find_in_aot_func = func;
936 mono_jit_info_get_code_start (MonoJitInfo* ji)
938 return ji->code_start;
942 mono_jit_info_get_code_size (MonoJitInfo* ji)
944 return ji->code_size;
948 mono_jit_info_get_method (MonoJitInfo* ji)
954 jit_info_key_extract (gpointer value)
956 MonoJitInfo *info = (MonoJitInfo*)value;
962 jit_info_next_value (gpointer value)
964 MonoJitInfo *info = (MonoJitInfo*)value;
966 return (gpointer*)&info->next_jit_code_hash;
970 mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
972 mono_internal_hash_table_init (jit_code_hash,
973 mono_aligned_addr_hash,
974 jit_info_key_extract,
975 jit_info_next_value);
979 mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
981 if (ji->has_generic_jit_info)
982 return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
988 * mono_jit_info_get_generic_sharing_context:
991 * Returns the jit info's generic sharing context, or NULL if it
994 MonoGenericSharingContext*
995 mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
997 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
1000 return gi->generic_sharing_context;
1006 * mono_jit_info_set_generic_sharing_context:
1008 * @gsctx: a generic sharing context
1010 * Sets the jit info's generic sharing context. The jit info must
1011 * have memory allocated for the context.
1014 mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
1016 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
1020 gi->generic_sharing_context = gsctx;
1023 MonoTryBlockHoleTableJitInfo*
1024 mono_jit_info_get_try_block_hole_table_info (MonoJitInfo *ji)
1026 if (ji->has_try_block_holes) {
1027 char *ptr = (char*)&ji->clauses [ji->num_clauses];
1028 if (ji->has_generic_jit_info)
1029 ptr += sizeof (MonoGenericJitInfo);
1030 return (MonoTryBlockHoleTableJitInfo*)ptr;
1036 mono_install_create_domain_hook (MonoCreateDomainFunc func)
1038 create_domain_hook = func;
1042 mono_install_free_domain_hook (MonoFreeDomainFunc func)
1044 free_domain_hook = func;
1048 * mono_string_equal:
1049 * @s1: First string to compare
1050 * @s2: Second string to compare
1052 * Returns FALSE if the strings differ.
1055 mono_string_equal (MonoString *s1, MonoString *s2)
1057 int l1 = mono_string_length (s1);
1058 int l2 = mono_string_length (s2);
1065 return memcmp (mono_string_chars (s1), mono_string_chars (s2), l1 * 2) == 0;
1070 * @s: the string to hash
1072 * Returns the hash for the string.
1075 mono_string_hash (MonoString *s)
1077 const guint16 *p = mono_string_chars (s);
1078 int i, len = mono_string_length (s);
1081 for (i = 0; i < len; i++) {
1082 h = (h << 5) - h + *p;
1090 mono_ptrarray_equal (gpointer *s1, gpointer *s2)
1092 int len = GPOINTER_TO_INT (s1 [0]);
1093 if (len != GPOINTER_TO_INT (s2 [0]))
1096 return memcmp (s1 + 1, s2 + 1, len * sizeof(gpointer)) == 0;
1100 mono_ptrarray_hash (gpointer *s)
1103 int len = GPOINTER_TO_INT (s [0]);
1106 for (i = 1; i < len; i++)
1107 hash += GPOINTER_TO_UINT (s [i]);
1113 * Allocate an id for domain and set domain->domain_id.
1114 * LOCKING: must be called while holding appdomains_mutex.
1115 * We try to assign low numbers to the domain, so it can be used
1116 * as an index in data tables to lookup domain-specific info
1117 * with minimal memory overhead. We also try not to reuse the
1118 * same id too quickly (to help debugging).
1121 domain_id_alloc (MonoDomain *domain)
1124 if (!appdomains_list) {
1125 appdomain_list_size = 2;
1126 appdomains_list = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1128 for (i = appdomain_next; i < appdomain_list_size; ++i) {
1129 if (!appdomains_list [i]) {
1135 for (i = 0; i < appdomain_next; ++i) {
1136 if (!appdomains_list [i]) {
1143 MonoDomain **new_list;
1144 int new_size = appdomain_list_size * 2;
1145 if (new_size >= (1 << 16))
1146 g_assert_not_reached ();
1147 id = appdomain_list_size;
1148 new_list = mono_gc_alloc_fixed (new_size * sizeof (void*), NULL);
1149 memcpy (new_list, appdomains_list, appdomain_list_size * sizeof (void*));
1150 mono_gc_free_fixed (appdomains_list);
1151 appdomains_list = new_list;
1152 appdomain_list_size = new_size;
1154 domain->domain_id = id;
1155 appdomains_list [id] = domain;
1157 if (appdomain_next > appdomain_list_size)
1162 static gsize domain_gc_bitmap [sizeof(MonoDomain)/4/32 + 1];
1163 static gpointer domain_gc_desc = NULL;
1164 static guint32 domain_shadow_serial = 0L;
1167 mono_domain_create (void)
1170 guint32 shadow_serial;
1172 mono_appdomains_lock ();
1173 shadow_serial = domain_shadow_serial++;
1175 if (!domain_gc_desc) {
1176 unsigned int i, bit = 0;
1177 for (i = G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_OBJECT); i < G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_GC_TRACKED); i += sizeof (gpointer)) {
1178 bit = i / sizeof (gpointer);
1179 domain_gc_bitmap [bit / 32] |= (gsize) 1 << (bit % 32);
1181 domain_gc_desc = mono_gc_make_descr_from_bitmap ((gsize*)domain_gc_bitmap, bit + 1);
1183 mono_appdomains_unlock ();
1185 #ifdef HAVE_BOEHM_GC
1187 * Boehm doesn't like roots inside GC allocated objects, and alloc_fixed returns
1188 * a GC_MALLOC-ed object, contrary to the api docs. This causes random crashes when
1189 * running the corlib test suite.
1190 * To solve this, we pass a NULL descriptor, and don't register roots.
1192 domain = mono_gc_alloc_fixed (sizeof (MonoDomain), NULL);
1194 domain = mono_gc_alloc_fixed (sizeof (MonoDomain), domain_gc_desc);
1195 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);
1197 domain->shadow_serial = shadow_serial;
1198 domain->domain = NULL;
1199 domain->setup = NULL;
1200 domain->friendly_name = NULL;
1201 domain->search_path = NULL;
1203 mono_profiler_appdomain_event (domain, MONO_PROFILE_START_LOAD);
1205 domain->mp = mono_mempool_new ();
1206 domain->code_mp = mono_code_manager_new ();
1207 domain->env = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1208 domain->domain_assemblies = NULL;
1209 domain->assembly_bindings = NULL;
1210 domain->assembly_bindings_parsed = FALSE;
1211 domain->class_vtable_array = g_ptr_array_new ();
1212 domain->proxy_vtable_hash = g_hash_table_new ((GHashFunc)mono_ptrarray_hash, (GCompareFunc)mono_ptrarray_equal);
1213 domain->static_data_array = NULL;
1214 mono_jit_code_hash_init (&domain->jit_code_hash);
1215 domain->ldstr_table = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1216 domain->num_jit_info_tables = 1;
1217 domain->jit_info_table = jit_info_table_new (domain);
1218 domain->jit_info_free_queue = NULL;
1219 domain->finalizable_objects_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1220 domain->track_resurrection_handles_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1222 InitializeCriticalSection (&domain->lock);
1223 InitializeCriticalSection (&domain->assemblies_lock);
1224 InitializeCriticalSection (&domain->jit_code_hash_lock);
1225 InitializeCriticalSection (&domain->finalizable_objects_hash_lock);
1227 domain->method_rgctx_hash = NULL;
1229 mono_appdomains_lock ();
1230 domain_id_alloc (domain);
1231 mono_appdomains_unlock ();
1233 mono_perfcounters->loader_appdomains++;
1234 mono_perfcounters->loader_total_appdomains++;
1236 mono_debug_domain_create (domain);
1238 if (create_domain_hook)
1239 create_domain_hook (domain);
1241 mono_profiler_appdomain_loaded (domain, MONO_PROFILE_OK);
1247 * mono_init_internal:
1249 * Creates the initial application domain and initializes the mono_defaults
1251 * This function is guaranteed to not run any IL code.
1252 * If exe_filename is not NULL, the method will determine the required runtime
1253 * from the exe configuration file or the version PE field.
1254 * If runtime_version is not NULL, that runtime version will be used.
1255 * Either exe_filename or runtime_version must be provided.
1257 * Returns: the initial domain.
1260 mono_init_internal (const char *filename, const char *exe_filename, const char *runtime_version)
1262 static MonoDomain *domain = NULL;
1263 MonoAssembly *ass = NULL;
1264 MonoImageOpenStatus status = MONO_IMAGE_OK;
1265 const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
1269 g_assert_not_reached ();
1272 /* Avoid system error message boxes. */
1273 SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1275 mono_load_coree (exe_filename);
1278 mono_perfcounters_init ();
1280 mono_counters_register ("Max native code in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_size);
1281 mono_counters_register ("Max code space allocated in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_alloc);
1282 mono_counters_register ("Total code space allocated", MONO_COUNTER_INT|MONO_COUNTER_JIT, &total_domain_code_alloc);
1284 mono_gc_base_init ();
1286 appdomain_thread_id = TlsAlloc ();
1288 InitializeCriticalSection (&appdomains_mutex);
1290 mono_metadata_init ();
1291 mono_images_init ();
1292 mono_assemblies_init ();
1293 mono_classes_init ();
1294 mono_loader_init ();
1295 mono_reflection_init ();
1297 /* FIXME: When should we release this memory? */
1298 MONO_GC_REGISTER_ROOT_FIXED (appdomains_list);
1300 domain = mono_domain_create ();
1301 mono_root_domain = domain;
1303 SET_APPDOMAIN (domain);
1305 /* Get a list of runtimes supported by the exe */
1306 if (exe_filename != NULL) {
1308 * This function will load the exe file as a MonoImage. We need to close it, but
1309 * that would mean it would be reloaded later. So instead, we save it to
1310 * exe_image, and close it during shutdown.
1312 get_runtimes_from_exe (exe_filename, &exe_image, runtimes);
1315 exe_image = mono_assembly_open_from_bundle (exe_filename, NULL, FALSE);
1317 exe_image = mono_image_open (exe_filename, NULL);
1319 mono_fixup_exe_image (exe_image);
1321 } else if (runtime_version != NULL) {
1322 runtimes [0] = get_runtime_by_version (runtime_version);
1323 runtimes [1] = NULL;
1326 if (runtimes [0] == NULL) {
1327 const MonoRuntimeInfo *default_runtime = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
1328 runtimes [0] = default_runtime;
1329 runtimes [1] = NULL;
1330 g_print ("WARNING: The runtime version supported by this application is unavailable.\n");
1331 g_print ("Using default runtime: %s\n", default_runtime->runtime_version);
1334 /* The selected runtime will be the first one for which there is a mscrolib.dll */
1335 for (n = 0; runtimes [n] != NULL && ass == NULL; n++) {
1336 current_runtime = runtimes [n];
1337 ass = mono_assembly_load_corlib (current_runtime, &status);
1338 if (status != MONO_IMAGE_OK && status != MONO_IMAGE_ERROR_ERRNO)
1343 if ((status != MONO_IMAGE_OK) || (ass == NULL)) {
1345 case MONO_IMAGE_ERROR_ERRNO: {
1346 char *corlib_file = g_build_filename (mono_assembly_getrootdir (), "mono", current_runtime->framework_version, "mscorlib.dll", NULL);
1347 g_print ("The assembly mscorlib.dll was not found or could not be loaded.\n");
1348 g_print ("It should have been installed in the `%s' directory.\n", corlib_file);
1349 g_free (corlib_file);
1352 case MONO_IMAGE_IMAGE_INVALID:
1353 g_print ("The file %s/mscorlib.dll is an invalid CIL image\n",
1354 mono_assembly_getrootdir ());
1356 case MONO_IMAGE_MISSING_ASSEMBLYREF:
1357 g_print ("Missing assembly reference in %s/mscorlib.dll\n",
1358 mono_assembly_getrootdir ());
1361 /* to suppress compiler warning */
1367 mono_defaults.corlib = mono_assembly_get_image (ass);
1369 mono_defaults.object_class = mono_class_from_name (
1370 mono_defaults.corlib, "System", "Object");
1371 g_assert (mono_defaults.object_class != 0);
1373 mono_defaults.void_class = mono_class_from_name (
1374 mono_defaults.corlib, "System", "Void");
1375 g_assert (mono_defaults.void_class != 0);
1377 mono_defaults.boolean_class = mono_class_from_name (
1378 mono_defaults.corlib, "System", "Boolean");
1379 g_assert (mono_defaults.boolean_class != 0);
1381 mono_defaults.byte_class = mono_class_from_name (
1382 mono_defaults.corlib, "System", "Byte");
1383 g_assert (mono_defaults.byte_class != 0);
1385 mono_defaults.sbyte_class = mono_class_from_name (
1386 mono_defaults.corlib, "System", "SByte");
1387 g_assert (mono_defaults.sbyte_class != 0);
1389 mono_defaults.int16_class = mono_class_from_name (
1390 mono_defaults.corlib, "System", "Int16");
1391 g_assert (mono_defaults.int16_class != 0);
1393 mono_defaults.uint16_class = mono_class_from_name (
1394 mono_defaults.corlib, "System", "UInt16");
1395 g_assert (mono_defaults.uint16_class != 0);
1397 mono_defaults.int32_class = mono_class_from_name (
1398 mono_defaults.corlib, "System", "Int32");
1399 g_assert (mono_defaults.int32_class != 0);
1401 mono_defaults.uint32_class = mono_class_from_name (
1402 mono_defaults.corlib, "System", "UInt32");
1403 g_assert (mono_defaults.uint32_class != 0);
1405 mono_defaults.uint_class = mono_class_from_name (
1406 mono_defaults.corlib, "System", "UIntPtr");
1407 g_assert (mono_defaults.uint_class != 0);
1409 mono_defaults.int_class = mono_class_from_name (
1410 mono_defaults.corlib, "System", "IntPtr");
1411 g_assert (mono_defaults.int_class != 0);
1413 mono_defaults.int64_class = mono_class_from_name (
1414 mono_defaults.corlib, "System", "Int64");
1415 g_assert (mono_defaults.int64_class != 0);
1417 mono_defaults.uint64_class = mono_class_from_name (
1418 mono_defaults.corlib, "System", "UInt64");
1419 g_assert (mono_defaults.uint64_class != 0);
1421 mono_defaults.single_class = mono_class_from_name (
1422 mono_defaults.corlib, "System", "Single");
1423 g_assert (mono_defaults.single_class != 0);
1425 mono_defaults.double_class = mono_class_from_name (
1426 mono_defaults.corlib, "System", "Double");
1427 g_assert (mono_defaults.double_class != 0);
1429 mono_defaults.char_class = mono_class_from_name (
1430 mono_defaults.corlib, "System", "Char");
1431 g_assert (mono_defaults.char_class != 0);
1433 mono_defaults.string_class = mono_class_from_name (
1434 mono_defaults.corlib, "System", "String");
1435 g_assert (mono_defaults.string_class != 0);
1437 mono_defaults.enum_class = mono_class_from_name (
1438 mono_defaults.corlib, "System", "Enum");
1439 g_assert (mono_defaults.enum_class != 0);
1441 mono_defaults.array_class = mono_class_from_name (
1442 mono_defaults.corlib, "System", "Array");
1443 g_assert (mono_defaults.array_class != 0);
1445 mono_defaults.delegate_class = mono_class_from_name (
1446 mono_defaults.corlib, "System", "Delegate");
1447 g_assert (mono_defaults.delegate_class != 0 );
1449 mono_defaults.multicastdelegate_class = mono_class_from_name (
1450 mono_defaults.corlib, "System", "MulticastDelegate");
1451 g_assert (mono_defaults.multicastdelegate_class != 0 );
1453 mono_defaults.asyncresult_class = mono_class_from_name (
1454 mono_defaults.corlib, "System.Runtime.Remoting.Messaging",
1456 g_assert (mono_defaults.asyncresult_class != 0 );
1458 mono_defaults.manualresetevent_class = mono_class_from_name (
1459 mono_defaults.corlib, "System.Threading", "ManualResetEvent");
1460 g_assert (mono_defaults.manualresetevent_class != 0 );
1462 mono_defaults.typehandle_class = mono_class_from_name (
1463 mono_defaults.corlib, "System", "RuntimeTypeHandle");
1464 g_assert (mono_defaults.typehandle_class != 0);
1466 mono_defaults.methodhandle_class = mono_class_from_name (
1467 mono_defaults.corlib, "System", "RuntimeMethodHandle");
1468 g_assert (mono_defaults.methodhandle_class != 0);
1470 mono_defaults.fieldhandle_class = mono_class_from_name (
1471 mono_defaults.corlib, "System", "RuntimeFieldHandle");
1472 g_assert (mono_defaults.fieldhandle_class != 0);
1474 mono_defaults.systemtype_class = mono_class_from_name (
1475 mono_defaults.corlib, "System", "Type");
1476 g_assert (mono_defaults.systemtype_class != 0);
1478 mono_defaults.monotype_class = mono_class_from_name (
1479 mono_defaults.corlib, "System", "MonoType");
1480 g_assert (mono_defaults.monotype_class != 0);
1482 mono_defaults.exception_class = mono_class_from_name (
1483 mono_defaults.corlib, "System", "Exception");
1484 g_assert (mono_defaults.exception_class != 0);
1486 mono_defaults.threadabortexception_class = mono_class_from_name (
1487 mono_defaults.corlib, "System.Threading", "ThreadAbortException");
1488 g_assert (mono_defaults.threadabortexception_class != 0);
1490 mono_defaults.thread_class = mono_class_from_name (
1491 mono_defaults.corlib, "System.Threading", "Thread");
1492 g_assert (mono_defaults.thread_class != 0);
1494 mono_defaults.internal_thread_class = mono_class_from_name (
1495 mono_defaults.corlib, "System.Threading", "InternalThread");
1496 if (!mono_defaults.internal_thread_class) {
1497 /* This can happen with an old mscorlib */
1498 fprintf (stderr, "Corlib too old for this runtime.\n");
1499 fprintf (stderr, "Loaded from: %s\n",
1500 mono_defaults.corlib? mono_image_get_filename (mono_defaults.corlib): "unknown");
1504 mono_defaults.appdomain_class = mono_class_from_name (
1505 mono_defaults.corlib, "System", "AppDomain");
1506 g_assert (mono_defaults.appdomain_class != 0);
1508 mono_defaults.transparent_proxy_class = mono_class_from_name (
1509 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "TransparentProxy");
1510 g_assert (mono_defaults.transparent_proxy_class != 0);
1512 mono_defaults.real_proxy_class = mono_class_from_name (
1513 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "RealProxy");
1514 g_assert (mono_defaults.real_proxy_class != 0);
1516 mono_defaults.mono_method_message_class = mono_class_from_name (
1517 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", "MonoMethodMessage");
1518 g_assert (mono_defaults.mono_method_message_class != 0);
1520 mono_defaults.field_info_class = mono_class_from_name (
1521 mono_defaults.corlib, "System.Reflection", "FieldInfo");
1522 g_assert (mono_defaults.field_info_class != 0);
1524 mono_defaults.method_info_class = mono_class_from_name (
1525 mono_defaults.corlib, "System.Reflection", "MethodInfo");
1526 g_assert (mono_defaults.method_info_class != 0);
1528 mono_defaults.stringbuilder_class = mono_class_from_name (
1529 mono_defaults.corlib, "System.Text", "StringBuilder");
1530 g_assert (mono_defaults.stringbuilder_class != 0);
1532 mono_defaults.math_class = mono_class_from_name (
1533 mono_defaults.corlib, "System", "Math");
1534 g_assert (mono_defaults.math_class != 0);
1536 mono_defaults.stack_frame_class = mono_class_from_name (
1537 mono_defaults.corlib, "System.Diagnostics", "StackFrame");
1538 g_assert (mono_defaults.stack_frame_class != 0);
1540 mono_defaults.stack_trace_class = mono_class_from_name (
1541 mono_defaults.corlib, "System.Diagnostics", "StackTrace");
1542 g_assert (mono_defaults.stack_trace_class != 0);
1544 mono_defaults.marshal_class = mono_class_from_name (
1545 mono_defaults.corlib, "System.Runtime.InteropServices", "Marshal");
1546 g_assert (mono_defaults.marshal_class != 0);
1548 mono_defaults.iserializeable_class = mono_class_from_name (
1549 mono_defaults.corlib, "System.Runtime.Serialization", "ISerializable");
1550 g_assert (mono_defaults.iserializeable_class != 0);
1552 mono_defaults.serializationinfo_class = mono_class_from_name (
1553 mono_defaults.corlib, "System.Runtime.Serialization", "SerializationInfo");
1554 g_assert (mono_defaults.serializationinfo_class != 0);
1556 mono_defaults.streamingcontext_class = mono_class_from_name (
1557 mono_defaults.corlib, "System.Runtime.Serialization", "StreamingContext");
1558 g_assert (mono_defaults.streamingcontext_class != 0);
1560 mono_defaults.typed_reference_class = mono_class_from_name (
1561 mono_defaults.corlib, "System", "TypedReference");
1562 g_assert (mono_defaults.typed_reference_class != 0);
1564 mono_defaults.argumenthandle_class = mono_class_from_name (
1565 mono_defaults.corlib, "System", "RuntimeArgumentHandle");
1566 g_assert (mono_defaults.argumenthandle_class != 0);
1568 mono_defaults.marshalbyrefobject_class = mono_class_from_name (
1569 mono_defaults.corlib, "System", "MarshalByRefObject");
1570 g_assert (mono_defaults.marshalbyrefobject_class != 0);
1572 mono_defaults.monitor_class = mono_class_from_name (
1573 mono_defaults.corlib, "System.Threading", "Monitor");
1574 g_assert (mono_defaults.monitor_class != 0);
1576 mono_defaults.iremotingtypeinfo_class = mono_class_from_name (
1577 mono_defaults.corlib, "System.Runtime.Remoting", "IRemotingTypeInfo");
1578 g_assert (mono_defaults.iremotingtypeinfo_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 */
1611 mono_defaults.variant_class = NULL;
1612 mono_defaults.com_object_class = NULL;
1613 mono_defaults.com_interop_proxy_class = NULL;
1614 mono_defaults.iunknown_class = NULL;
1615 mono_defaults.idispatch_class = NULL;
1618 * Note that mono_defaults.generic_*_class is only non-NULL if we're
1619 * using the 2.0 corlib.
1621 mono_class_init (mono_defaults.array_class);
1622 mono_defaults.generic_nullable_class = mono_class_from_name (
1623 mono_defaults.corlib, "System", "Nullable`1");
1624 mono_defaults.generic_ilist_class = mono_class_from_name (
1625 mono_defaults.corlib, "System.Collections.Generic", "IList`1");
1627 domain->friendly_name = g_path_get_basename (filename);
1629 _mono_debug_init_corlib (domain);
1637 * Creates the initial application domain and initializes the mono_defaults
1639 * This function is guaranteed to not run any IL code.
1640 * The runtime is initialized using the default runtime version.
1642 * Returns: the initial domain.
1645 mono_init (const char *domain_name)
1647 return mono_init_internal (domain_name, NULL, DEFAULT_RUNTIME_VERSION);
1651 * mono_init_from_assembly:
1652 * @domain_name: name to give to the initial domain
1653 * @filename: filename to load on startup
1655 * Used by the runtime, users should use mono_jit_init instead.
1657 * Creates the initial application domain and initializes the mono_defaults
1659 * This function is guaranteed to not run any IL code.
1660 * The runtime is initialized using the runtime version required by the
1661 * provided executable. The version is determined by looking at the exe
1662 * configuration file and the version PE field)
1664 * Returns: the initial domain.
1667 mono_init_from_assembly (const char *domain_name, const char *filename)
1669 return mono_init_internal (domain_name, filename, NULL);
1673 * mono_init_version:
1675 * Used by the runtime, users should use mono_jit_init instead.
1677 * Creates the initial application domain and initializes the mono_defaults
1680 * This function is guaranteed to not run any IL code.
1681 * The runtime is initialized using the provided rutime version.
1683 * Returns: the initial domain.
1686 mono_init_version (const char *domain_name, const char *version)
1688 return mono_init_internal (domain_name, NULL, version);
1692 * mono_init_com_types:
1694 * Initializes all types needed for COM Interop in mono_defaults structure.
1697 mono_init_com_types (void)
1699 static gboolean initialized = FALSE;
1704 /* FIXME: do I need some threading protection here */
1706 g_assert (mono_defaults.corlib);
1708 mono_defaults.variant_class = mono_class_from_name (
1709 mono_defaults.corlib, "System", "Variant");
1710 g_assert (mono_defaults.variant_class != 0);
1712 mono_defaults.com_object_class = mono_class_from_name (
1713 mono_defaults.corlib, "System", "__ComObject");
1714 g_assert (mono_defaults.com_object_class != 0);
1716 mono_defaults.com_interop_proxy_class = mono_class_from_name (
1717 mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
1718 g_assert (mono_defaults.com_interop_proxy_class != 0);
1720 mono_defaults.iunknown_class = mono_class_from_name (
1721 mono_defaults.corlib, "Mono.Interop", "IUnknown");
1722 g_assert (mono_defaults.iunknown_class != 0);
1724 mono_defaults.idispatch_class = mono_class_from_name (
1725 mono_defaults.corlib, "Mono.Interop", "IDispatch");
1726 g_assert (mono_defaults.idispatch_class != 0);
1734 * Cleans up all metadata modules.
1739 mono_close_exe_image ();
1741 mono_defaults.corlib = NULL;
1743 mono_config_cleanup ();
1744 mono_loader_cleanup ();
1745 mono_classes_cleanup ();
1746 mono_assemblies_cleanup ();
1747 mono_images_cleanup ();
1748 mono_debug_cleanup ();
1749 mono_metadata_cleanup ();
1751 TlsFree (appdomain_thread_id);
1752 DeleteCriticalSection (&appdomains_mutex);
1755 * This should be called last as TlsGetValue ()/TlsSetValue () can be called during
1764 mono_close_exe_image (void)
1767 mono_image_close (exe_image);
1771 * mono_get_root_domain:
1773 * The root AppDomain is the initial domain created by the runtime when it is
1774 * initialized. Programs execute on this AppDomain, but can create new ones
1775 * later. Currently there is no unmanaged API to create new AppDomains, this
1776 * must be done from managed code.
1778 * Returns: the root appdomain, to obtain the current domain, use mono_domain_get ()
1781 mono_get_root_domain (void)
1783 return mono_root_domain;
1789 * Returns: the current domain, to obtain the root domain use
1790 * mono_get_root_domain().
1795 return GET_APPDOMAIN ();
1799 mono_domain_unset (void)
1801 SET_APPDOMAIN (NULL);
1805 mono_domain_set_internal_with_options (MonoDomain *domain, gboolean migrate_exception)
1807 MonoInternalThread *thread;
1809 if (mono_domain_get () == domain)
1812 SET_APPDOMAIN (domain);
1813 SET_APPCONTEXT (domain->default_context);
1815 if (migrate_exception) {
1816 thread = mono_thread_internal_current ();
1817 if (!thread->abort_exc)
1820 g_assert (thread->abort_exc->object.vtable->domain != domain);
1821 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
1822 g_assert (thread->abort_exc->object.vtable->domain == domain);
1827 * mono_domain_set_internal:
1828 * @domain: the new domain
1830 * Sets the current domain to @domain.
1833 mono_domain_set_internal (MonoDomain *domain)
1835 mono_domain_set_internal_with_options (domain, TRUE);
1839 mono_domain_foreach (MonoDomainFunc func, gpointer user_data)
1845 * Create a copy of the data to avoid calling the user callback
1846 * inside the lock because that could lead to deadlocks.
1847 * We can do this because this function is not perf. critical.
1849 mono_appdomains_lock ();
1850 size = appdomain_list_size;
1851 copy = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1852 memcpy (copy, appdomains_list, appdomain_list_size * sizeof (void*));
1853 mono_appdomains_unlock ();
1855 for (i = 0; i < size; ++i) {
1857 func (copy [i], user_data);
1860 mono_gc_free_fixed (copy);
1864 * mono_domain_assembly_open:
1865 * @domain: the application domain
1866 * @name: file name of the assembly
1868 * fixme: maybe we should integrate this with mono_assembly_open ??
1871 mono_domain_assembly_open (MonoDomain *domain, const char *name)
1873 MonoDomain *current;
1877 mono_domain_assemblies_lock (domain);
1878 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1880 if (strcmp (name, ass->aname.name) == 0) {
1881 mono_domain_assemblies_unlock (domain);
1885 mono_domain_assemblies_unlock (domain);
1887 if (domain != mono_domain_get ()) {
1888 current = mono_domain_get ();
1890 mono_domain_set (domain, FALSE);
1891 ass = mono_assembly_open (name, NULL);
1892 mono_domain_set (current, FALSE);
1894 ass = mono_assembly_open (name, NULL);
1901 free_slist (gpointer key, gpointer value, gpointer user_data)
1903 g_slist_free (value);
1907 unregister_vtable_reflection_type (MonoVTable *vtable)
1909 MonoObject *type = vtable->type;
1911 if (type->vtable->klass != mono_defaults.monotype_class)
1912 MONO_GC_UNREGISTER_ROOT_IF_MOVING (vtable->type);
1916 mono_domain_free (MonoDomain *domain, gboolean force)
1918 int code_size, code_alloc;
1920 if ((domain == mono_root_domain) && !force) {
1921 g_warning ("cant unload root domain");
1925 if (mono_dont_free_domains)
1928 mono_profiler_appdomain_event (domain, MONO_PROFILE_START_UNLOAD);
1930 mono_debug_domain_unload (domain);
1932 mono_appdomains_lock ();
1933 appdomains_list [domain->domain_id] = NULL;
1934 mono_appdomains_unlock ();
1936 /* must do this early as it accesses fields and types */
1937 if (domain->special_static_fields) {
1938 mono_alloc_special_static_data_free (domain->special_static_fields);
1939 g_hash_table_destroy (domain->special_static_fields);
1940 domain->special_static_fields = NULL;
1944 * We must destroy all these hash tables here because they
1945 * contain references to managed objects belonging to the
1946 * domain. Once we let the GC clear the domain there must be
1947 * no more such references, or we'll crash if a collection
1950 mono_g_hash_table_destroy (domain->ldstr_table);
1951 domain->ldstr_table = NULL;
1953 mono_g_hash_table_destroy (domain->env);
1956 mono_reflection_cleanup_domain (domain);
1958 if (domain->type_hash) {
1959 mono_g_hash_table_destroy (domain->type_hash);
1960 domain->type_hash = NULL;
1962 if (domain->type_init_exception_hash) {
1963 mono_g_hash_table_destroy (domain->type_init_exception_hash);
1964 domain->type_init_exception_hash = NULL;
1967 if (domain->class_vtable_array) {
1969 for (i = 0; i < domain->class_vtable_array->len; ++i)
1970 unregister_vtable_reflection_type (g_ptr_array_index (domain->class_vtable_array, i));
1973 /* This needs to be done before closing assemblies */
1974 mono_gc_clear_domain (domain);
1976 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1977 MonoAssembly *ass = tmp->data;
1978 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading domain %s[%p], assembly %s[%p], ref_count=%d\n", domain->friendly_name, domain, ass->aname.name, ass, ass->ref_count);
1979 if (!mono_assembly_close_except_image_pools (ass))
1983 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1984 MonoAssembly *ass = tmp->data;
1986 mono_assembly_close_finish (ass);
1988 g_slist_free (domain->domain_assemblies);
1989 domain->domain_assemblies = NULL;
1992 * Send this after the assemblies have been unloaded and the domain is still in a
1995 mono_profiler_appdomain_event (domain, MONO_PROFILE_END_UNLOAD);
1997 if (free_domain_hook)
1998 free_domain_hook (domain);
2000 /* FIXME: free delegate_hash_table when it's used */
2001 if (domain->search_path) {
2002 g_strfreev (domain->search_path);
2003 domain->search_path = NULL;
2005 domain->create_proxy_for_type_method = NULL;
2006 domain->private_invoke_method = NULL;
2007 domain->default_context = NULL;
2008 domain->out_of_memory_ex = NULL;
2009 domain->null_reference_ex = NULL;
2010 domain->stack_overflow_ex = NULL;
2011 domain->ephemeron_tombstone = NULL;
2012 domain->entry_assembly = NULL;
2014 g_free (domain->friendly_name);
2015 domain->friendly_name = NULL;
2016 g_ptr_array_free (domain->class_vtable_array, TRUE);
2017 domain->class_vtable_array = NULL;
2018 g_hash_table_destroy (domain->proxy_vtable_hash);
2019 domain->proxy_vtable_hash = NULL;
2020 if (domain->static_data_array) {
2021 mono_gc_free_fixed (domain->static_data_array);
2022 domain->static_data_array = NULL;
2024 mono_internal_hash_table_destroy (&domain->jit_code_hash);
2027 * There might still be jit info tables of this domain which
2028 * are not freed. Since the domain cannot be in use anymore,
2029 * this will free them.
2031 mono_thread_hazardous_try_free_all ();
2032 g_assert (domain->num_jit_info_tables == 1);
2033 jit_info_table_free (domain->jit_info_table);
2034 domain->jit_info_table = NULL;
2035 g_assert (!domain->jit_info_free_queue);
2037 /* collect statistics */
2038 code_alloc = mono_code_manager_size (domain->code_mp, &code_size);
2039 total_domain_code_alloc += code_alloc;
2040 max_domain_code_alloc = MAX (max_domain_code_alloc, code_alloc);
2041 max_domain_code_size = MAX (max_domain_code_size, code_size);
2043 #ifdef DEBUG_DOMAIN_UNLOAD
2044 mono_mempool_invalidate (domain->mp);
2045 mono_code_manager_invalidate (domain->code_mp);
2047 mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (domain->mp);
2048 mono_mempool_destroy (domain->mp);
2050 mono_code_manager_destroy (domain->code_mp);
2051 domain->code_mp = NULL;
2054 g_hash_table_destroy (domain->finalizable_objects_hash);
2055 domain->finalizable_objects_hash = NULL;
2056 if (domain->track_resurrection_objects_hash) {
2057 g_hash_table_foreach (domain->track_resurrection_objects_hash, free_slist, NULL);
2058 g_hash_table_destroy (domain->track_resurrection_objects_hash);
2060 if (domain->track_resurrection_handles_hash)
2061 g_hash_table_destroy (domain->track_resurrection_handles_hash);
2062 if (domain->method_rgctx_hash) {
2063 g_hash_table_destroy (domain->method_rgctx_hash);
2064 domain->method_rgctx_hash = NULL;
2066 if (domain->generic_virtual_cases) {
2067 g_hash_table_destroy (domain->generic_virtual_cases);
2068 domain->generic_virtual_cases = NULL;
2071 DeleteCriticalSection (&domain->finalizable_objects_hash_lock);
2072 DeleteCriticalSection (&domain->assemblies_lock);
2073 DeleteCriticalSection (&domain->jit_code_hash_lock);
2074 DeleteCriticalSection (&domain->lock);
2075 domain->setup = NULL;
2077 mono_gc_deregister_root ((char*)&(domain->MONO_DOMAIN_FIRST_GC_TRACKED));
2079 /* FIXME: anything else required ? */
2081 mono_gc_free_fixed (domain);
2083 mono_perfcounters->loader_appdomains--;
2085 if ((domain == mono_root_domain))
2086 mono_root_domain = NULL;
2090 * mono_domain_get_id:
2093 * Returns: the a domain for a specific domain id.
2096 mono_domain_get_by_id (gint32 domainid)
2098 MonoDomain * domain;
2100 mono_appdomains_lock ();
2101 if (domainid < appdomain_list_size)
2102 domain = appdomains_list [domainid];
2105 mono_appdomains_unlock ();
2111 mono_domain_get_id (MonoDomain *domain)
2113 return domain->domain_id;
2117 * mono_domain_alloc:
2119 * LOCKING: Acquires the domain lock.
2122 mono_domain_alloc (MonoDomain *domain, guint size)
2126 mono_domain_lock (domain);
2127 mono_perfcounters->loader_bytes += size;
2128 res = mono_mempool_alloc (domain->mp, size);
2129 mono_domain_unlock (domain);
2135 * mono_domain_alloc0:
2137 * LOCKING: Acquires the domain lock.
2140 mono_domain_alloc0 (MonoDomain *domain, guint size)
2144 mono_domain_lock (domain);
2145 mono_perfcounters->loader_bytes += size;
2146 res = mono_mempool_alloc0 (domain->mp, size);
2147 mono_domain_unlock (domain);
2153 * mono_domain_code_reserve:
2155 * LOCKING: Acquires the domain lock.
2158 mono_domain_code_reserve (MonoDomain *domain, int size)
2162 mono_domain_lock (domain);
2163 res = mono_code_manager_reserve (domain->code_mp, size);
2164 mono_domain_unlock (domain);
2170 * mono_domain_code_reserve_align:
2172 * LOCKING: Acquires the domain lock.
2175 mono_domain_code_reserve_align (MonoDomain *domain, int size, int alignment)
2179 mono_domain_lock (domain);
2180 res = mono_code_manager_reserve_align (domain->code_mp, size, alignment);
2181 mono_domain_unlock (domain);
2187 * mono_domain_code_commit:
2189 * LOCKING: Acquires the domain lock.
2192 mono_domain_code_commit (MonoDomain *domain, void *data, int size, int newsize)
2194 mono_domain_lock (domain);
2195 mono_code_manager_commit (domain->code_mp, data, size, newsize);
2196 mono_domain_unlock (domain);
2199 #if defined(__native_client_codegen__) && defined(__native_client__)
2201 * Given the temporary buffer (allocated by mono_domain_code_reserve) into which
2202 * we are generating code, return a pointer to the destination in the dynamic
2203 * code segment into which the code will be copied when mono_domain_code_commit
2205 * LOCKING: Acquires the domain lock.
2208 nacl_domain_get_code_dest (MonoDomain *domain, void *data)
2211 mono_domain_lock (domain);
2212 dest = nacl_code_manager_get_code_dest (domain->code_mp, data);
2213 mono_domain_unlock (domain);
2218 * Convenience function which calls mono_domain_code_commit to validate and copy
2219 * the code. The caller sets *buf_base and *buf_size to the start and size of
2220 * the buffer (allocated by mono_domain_code_reserve), and *code_end to the byte
2221 * after the last instruction byte. On return, *buf_base will point to the start
2222 * of the copied in the code segment, and *code_end will point after the end of
2226 nacl_domain_code_validate (MonoDomain *domain, guint8 **buf_base, int buf_size, guint8 **code_end)
2228 guint8 *tmp = nacl_domain_get_code_dest (domain, *buf_base);
2229 mono_domain_code_commit (domain, *buf_base, buf_size, *code_end - *buf_base);
2230 *code_end = tmp + (*code_end - *buf_base);
2236 * mono_domain_code_foreach:
2237 * Iterate over the code thunks of the code manager of @domain.
2239 * The @func callback MUST not take any locks. If it really needs to, it must respect
2240 * the locking rules of the runtime: http://www.mono-project.com/Mono:Runtime:Documentation:ThreadSafety
2241 * LOCKING: Acquires the domain lock.
2245 mono_domain_code_foreach (MonoDomain *domain, MonoCodeManagerFunc func, void *user_data)
2247 mono_domain_lock (domain);
2248 mono_code_manager_foreach (domain->code_mp, func, user_data);
2249 mono_domain_unlock (domain);
2254 mono_context_set (MonoAppContext * new_context)
2256 SET_APPCONTEXT (new_context);
2260 mono_context_get (void)
2262 return GET_APPCONTEXT ();
2265 /* LOCKING: the caller holds the lock for this domain */
2267 mono_domain_add_class_static_data (MonoDomain *domain, MonoClass *klass, gpointer data, guint32 *bitmap)
2269 /* The first entry in the array is the index of the next free slot
2270 * and the total size of the array
2273 if (domain->static_data_array) {
2274 int size = GPOINTER_TO_INT (domain->static_data_array [1]);
2275 next = GPOINTER_TO_INT (domain->static_data_array [0]);
2277 /* 'data' is allocated by alloc_fixed */
2278 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * (size * 2), MONO_GC_ROOT_DESCR_FOR_FIXED (size * 2));
2279 memcpy (new_array, domain->static_data_array, sizeof (gpointer) * size);
2281 new_array [1] = GINT_TO_POINTER (size);
2282 mono_gc_free_fixed (domain->static_data_array);
2283 domain->static_data_array = new_array;
2287 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * size, MONO_GC_ROOT_DESCR_FOR_FIXED (size));
2289 new_array [0] = GINT_TO_POINTER (next);
2290 new_array [1] = GINT_TO_POINTER (size);
2291 domain->static_data_array = new_array;
2293 domain->static_data_array [next++] = data;
2294 domain->static_data_array [0] = GINT_TO_POINTER (next);
2298 mono_get_corlib (void)
2300 return mono_defaults.corlib;
2304 mono_get_object_class (void)
2306 return mono_defaults.object_class;
2310 mono_get_byte_class (void)
2312 return mono_defaults.byte_class;
2316 mono_get_void_class (void)
2318 return mono_defaults.void_class;
2322 mono_get_boolean_class (void)
2324 return mono_defaults.boolean_class;
2328 mono_get_sbyte_class (void)
2330 return mono_defaults.sbyte_class;
2334 mono_get_int16_class (void)
2336 return mono_defaults.int16_class;
2340 mono_get_uint16_class (void)
2342 return mono_defaults.uint16_class;
2346 mono_get_int32_class (void)
2348 return mono_defaults.int32_class;
2352 mono_get_uint32_class (void)
2354 return mono_defaults.uint32_class;
2358 mono_get_intptr_class (void)
2360 return mono_defaults.int_class;
2364 mono_get_uintptr_class (void)
2366 return mono_defaults.uint_class;
2370 mono_get_int64_class (void)
2372 return mono_defaults.int64_class;
2376 mono_get_uint64_class (void)
2378 return mono_defaults.uint64_class;
2382 mono_get_single_class (void)
2384 return mono_defaults.single_class;
2388 mono_get_double_class (void)
2390 return mono_defaults.double_class;
2394 mono_get_char_class (void)
2396 return mono_defaults.char_class;
2400 mono_get_string_class (void)
2402 return mono_defaults.string_class;
2406 mono_get_enum_class (void)
2408 return mono_defaults.enum_class;
2412 mono_get_array_class (void)
2414 return mono_defaults.array_class;
2418 mono_get_thread_class (void)
2420 return mono_defaults.thread_class;
2424 mono_get_exception_class (void)
2426 return mono_defaults.exception_class;
2430 static char* get_attribute_value (const gchar **attribute_names,
2431 const gchar **attribute_values,
2432 const char *att_name)
2435 for (n=0; attribute_names[n] != NULL; n++) {
2436 if (strcmp (attribute_names[n], att_name) == 0)
2437 return g_strdup (attribute_values[n]);
2442 static void start_element (GMarkupParseContext *context,
2443 const gchar *element_name,
2444 const gchar **attribute_names,
2445 const gchar **attribute_values,
2449 AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2451 if (strcmp (element_name, "configuration") == 0) {
2452 app_config->configuration_count++;
2455 if (strcmp (element_name, "startup") == 0) {
2456 app_config->startup_count++;
2460 if (app_config->configuration_count != 1 || app_config->startup_count != 1)
2463 if (strcmp (element_name, "requiredRuntime") == 0) {
2464 app_config->required_runtime = get_attribute_value (attribute_names, attribute_values, "version");
2465 } else if (strcmp (element_name, "supportedRuntime") == 0) {
2466 char *version = get_attribute_value (attribute_names, attribute_values, "version");
2467 app_config->supported_runtimes = g_slist_append (app_config->supported_runtimes, version);
2471 static void end_element (GMarkupParseContext *context,
2472 const gchar *element_name,
2476 AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2478 if (strcmp (element_name, "configuration") == 0) {
2479 app_config->configuration_count--;
2480 } else if (strcmp (element_name, "startup") == 0) {
2481 app_config->startup_count--;
2485 static const GMarkupParser
2494 static AppConfigInfo *
2495 app_config_parse (const char *exe_filename)
2497 AppConfigInfo *app_config;
2498 GMarkupParseContext *context;
2501 const char *bundled_config;
2502 char *config_filename;
2504 bundled_config = mono_config_string_for_assembly_file (exe_filename);
2506 if (bundled_config) {
2507 text = g_strdup (bundled_config);
2508 len = strlen (text);
2510 config_filename = g_strconcat (exe_filename, ".config", NULL);
2512 if (!g_file_get_contents (config_filename, &text, &len, NULL)) {
2513 g_free (config_filename);
2516 g_free (config_filename);
2519 app_config = g_new0 (AppConfigInfo, 1);
2521 context = g_markup_parse_context_new (&mono_parser, 0, app_config, NULL);
2522 if (g_markup_parse_context_parse (context, text, len, NULL)) {
2523 g_markup_parse_context_end_parse (context, NULL);
2525 g_markup_parse_context_free (context);
2531 app_config_free (AppConfigInfo* app_config)
2534 GSList *list = app_config->supported_runtimes;
2535 while (list != NULL) {
2536 rt = (char*)list->data;
2538 list = g_slist_next (list);
2540 g_slist_free (app_config->supported_runtimes);
2541 g_free (app_config->required_runtime);
2542 g_free (app_config);
2546 static const MonoRuntimeInfo*
2547 get_runtime_by_version (const char *version)
2550 int max = G_N_ELEMENTS (supported_runtimes);
2551 gboolean do_partial_match;
2557 vlen = strlen (version);
2558 if (vlen >= 4 && version [1] - '0' >= 4)
2559 do_partial_match = TRUE;
2561 do_partial_match = FALSE;
2563 for (n=0; n<max; n++) {
2564 if (do_partial_match && strncmp (version, supported_runtimes[n].runtime_version, vlen) == 0)
2565 return &supported_runtimes[n];
2566 if (strcmp (version, supported_runtimes[n].runtime_version) == 0)
2567 return &supported_runtimes[n];
2573 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes)
2575 AppConfigInfo* app_config;
2577 const MonoRuntimeInfo* runtime = NULL;
2578 MonoImage *image = NULL;
2580 app_config = app_config_parse (exe_file);
2582 if (app_config != NULL) {
2583 /* Check supportedRuntime elements, if none is supported, fail.
2584 * If there are no such elements, look for a requiredRuntime element.
2586 if (app_config->supported_runtimes != NULL) {
2588 GSList *list = app_config->supported_runtimes;
2589 while (list != NULL) {
2590 version = (char*) list->data;
2591 runtime = get_runtime_by_version (version);
2592 if (runtime != NULL)
2593 runtimes [n++] = runtime;
2594 list = g_slist_next (list);
2596 runtimes [n] = NULL;
2597 app_config_free (app_config);
2601 /* Check the requiredRuntime element. This is for 1.0 apps only. */
2602 if (app_config->required_runtime != NULL) {
2603 runtimes [0] = get_runtime_by_version (app_config->required_runtime);
2604 runtimes [1] = NULL;
2605 app_config_free (app_config);
2608 app_config_free (app_config);
2611 /* Look for a runtime with the exact version */
2612 image = mono_assembly_open_from_bundle (exe_file, NULL, FALSE);
2615 image = mono_image_open (exe_file, NULL);
2617 if (image == NULL) {
2618 /* The image is wrong or the file was not found. In this case return
2619 * a default runtime and leave to the initialization method the work of
2620 * reporting the error.
2622 runtimes [0] = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
2623 runtimes [1] = NULL;
2629 runtimes [0] = get_runtime_by_version (image->version);
2630 runtimes [1] = NULL;
2635 * mono_get_runtime_info:
2637 * Returns: the version of the current runtime instance.
2639 const MonoRuntimeInfo*
2640 mono_get_runtime_info (void)
2642 return current_runtime;
2646 mono_debugger_check_runtime_version (const char *filename)
2648 const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
2649 const MonoRuntimeInfo *rinfo;
2652 get_runtimes_from_exe (filename, &image, runtimes);
2653 rinfo = runtimes [0];
2656 return g_strdup_printf ("Cannot get runtime version from assembly `%s'", filename);
2658 if (rinfo != current_runtime)
2659 return g_strdup_printf ("The Mono Debugger is currently using the `%s' runtime, but "
2660 "the assembly `%s' requires version `%s'", current_runtime->runtime_version,
2661 filename, rinfo->runtime_version);
2667 * mono_framework_version:
2669 * Return the major version of the framework curently executing.
2672 mono_framework_version (void)
2674 return current_runtime->framework_version [0] - '0';