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);
1279 mono_perfcounters_init ();
1281 mono_counters_register ("Max native code in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_size);
1282 mono_counters_register ("Max code space allocated in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_alloc);
1283 mono_counters_register ("Total code space allocated", MONO_COUNTER_INT|MONO_COUNTER_JIT, &total_domain_code_alloc);
1285 mono_gc_base_init ();
1287 appdomain_thread_id = TlsAlloc ();
1289 InitializeCriticalSection (&appdomains_mutex);
1291 mono_metadata_init ();
1292 mono_images_init ();
1293 mono_assemblies_init ();
1294 mono_classes_init ();
1295 mono_loader_init ();
1296 mono_reflection_init ();
1298 /* FIXME: When should we release this memory? */
1299 MONO_GC_REGISTER_ROOT_FIXED (appdomains_list);
1301 domain = mono_domain_create ();
1302 mono_root_domain = domain;
1304 SET_APPDOMAIN (domain);
1306 /* Get a list of runtimes supported by the exe */
1307 if (exe_filename != NULL) {
1309 * This function will load the exe file as a MonoImage. We need to close it, but
1310 * that would mean it would be reloaded later. So instead, we save it to
1311 * exe_image, and close it during shutdown.
1313 get_runtimes_from_exe (exe_filename, &exe_image, runtimes);
1316 exe_image = mono_assembly_open_from_bundle (exe_filename, NULL, FALSE);
1318 exe_image = mono_image_open (exe_filename, NULL);
1320 mono_fixup_exe_image (exe_image);
1322 } else if (runtime_version != NULL) {
1323 runtimes [0] = get_runtime_by_version (runtime_version);
1324 runtimes [1] = NULL;
1327 if (runtimes [0] == NULL) {
1328 const MonoRuntimeInfo *default_runtime = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
1329 runtimes [0] = default_runtime;
1330 runtimes [1] = NULL;
1331 g_print ("WARNING: The runtime version supported by this application is unavailable.\n");
1332 g_print ("Using default runtime: %s\n", default_runtime->runtime_version);
1335 /* The selected runtime will be the first one for which there is a mscrolib.dll */
1336 for (n = 0; runtimes [n] != NULL && ass == NULL; n++) {
1337 current_runtime = runtimes [n];
1338 ass = mono_assembly_load_corlib (current_runtime, &status);
1339 if (status != MONO_IMAGE_OK && status != MONO_IMAGE_ERROR_ERRNO)
1344 if ((status != MONO_IMAGE_OK) || (ass == NULL)) {
1346 case MONO_IMAGE_ERROR_ERRNO: {
1347 char *corlib_file = g_build_filename (mono_assembly_getrootdir (), "mono", current_runtime->framework_version, "mscorlib.dll", NULL);
1348 g_print ("The assembly mscorlib.dll was not found or could not be loaded.\n");
1349 g_print ("It should have been installed in the `%s' directory.\n", corlib_file);
1350 g_free (corlib_file);
1353 case MONO_IMAGE_IMAGE_INVALID:
1354 g_print ("The file %s/mscorlib.dll is an invalid CIL image\n",
1355 mono_assembly_getrootdir ());
1357 case MONO_IMAGE_MISSING_ASSEMBLYREF:
1358 g_print ("Missing assembly reference in %s/mscorlib.dll\n",
1359 mono_assembly_getrootdir ());
1362 /* to suppress compiler warning */
1368 mono_defaults.corlib = mono_assembly_get_image (ass);
1370 mono_defaults.object_class = mono_class_from_name (
1371 mono_defaults.corlib, "System", "Object");
1372 g_assert (mono_defaults.object_class != 0);
1374 mono_defaults.void_class = mono_class_from_name (
1375 mono_defaults.corlib, "System", "Void");
1376 g_assert (mono_defaults.void_class != 0);
1378 mono_defaults.boolean_class = mono_class_from_name (
1379 mono_defaults.corlib, "System", "Boolean");
1380 g_assert (mono_defaults.boolean_class != 0);
1382 mono_defaults.byte_class = mono_class_from_name (
1383 mono_defaults.corlib, "System", "Byte");
1384 g_assert (mono_defaults.byte_class != 0);
1386 mono_defaults.sbyte_class = mono_class_from_name (
1387 mono_defaults.corlib, "System", "SByte");
1388 g_assert (mono_defaults.sbyte_class != 0);
1390 mono_defaults.int16_class = mono_class_from_name (
1391 mono_defaults.corlib, "System", "Int16");
1392 g_assert (mono_defaults.int16_class != 0);
1394 mono_defaults.uint16_class = mono_class_from_name (
1395 mono_defaults.corlib, "System", "UInt16");
1396 g_assert (mono_defaults.uint16_class != 0);
1398 mono_defaults.int32_class = mono_class_from_name (
1399 mono_defaults.corlib, "System", "Int32");
1400 g_assert (mono_defaults.int32_class != 0);
1402 mono_defaults.uint32_class = mono_class_from_name (
1403 mono_defaults.corlib, "System", "UInt32");
1404 g_assert (mono_defaults.uint32_class != 0);
1406 mono_defaults.uint_class = mono_class_from_name (
1407 mono_defaults.corlib, "System", "UIntPtr");
1408 g_assert (mono_defaults.uint_class != 0);
1410 mono_defaults.int_class = mono_class_from_name (
1411 mono_defaults.corlib, "System", "IntPtr");
1412 g_assert (mono_defaults.int_class != 0);
1414 mono_defaults.int64_class = mono_class_from_name (
1415 mono_defaults.corlib, "System", "Int64");
1416 g_assert (mono_defaults.int64_class != 0);
1418 mono_defaults.uint64_class = mono_class_from_name (
1419 mono_defaults.corlib, "System", "UInt64");
1420 g_assert (mono_defaults.uint64_class != 0);
1422 mono_defaults.single_class = mono_class_from_name (
1423 mono_defaults.corlib, "System", "Single");
1424 g_assert (mono_defaults.single_class != 0);
1426 mono_defaults.double_class = mono_class_from_name (
1427 mono_defaults.corlib, "System", "Double");
1428 g_assert (mono_defaults.double_class != 0);
1430 mono_defaults.char_class = mono_class_from_name (
1431 mono_defaults.corlib, "System", "Char");
1432 g_assert (mono_defaults.char_class != 0);
1434 mono_defaults.string_class = mono_class_from_name (
1435 mono_defaults.corlib, "System", "String");
1436 g_assert (mono_defaults.string_class != 0);
1438 mono_defaults.enum_class = mono_class_from_name (
1439 mono_defaults.corlib, "System", "Enum");
1440 g_assert (mono_defaults.enum_class != 0);
1442 mono_defaults.array_class = mono_class_from_name (
1443 mono_defaults.corlib, "System", "Array");
1444 g_assert (mono_defaults.array_class != 0);
1446 mono_defaults.delegate_class = mono_class_from_name (
1447 mono_defaults.corlib, "System", "Delegate");
1448 g_assert (mono_defaults.delegate_class != 0 );
1450 mono_defaults.multicastdelegate_class = mono_class_from_name (
1451 mono_defaults.corlib, "System", "MulticastDelegate");
1452 g_assert (mono_defaults.multicastdelegate_class != 0 );
1454 mono_defaults.asyncresult_class = mono_class_from_name (
1455 mono_defaults.corlib, "System.Runtime.Remoting.Messaging",
1457 g_assert (mono_defaults.asyncresult_class != 0 );
1459 mono_defaults.manualresetevent_class = mono_class_from_name (
1460 mono_defaults.corlib, "System.Threading", "ManualResetEvent");
1461 g_assert (mono_defaults.manualresetevent_class != 0 );
1463 mono_defaults.typehandle_class = mono_class_from_name (
1464 mono_defaults.corlib, "System", "RuntimeTypeHandle");
1465 g_assert (mono_defaults.typehandle_class != 0);
1467 mono_defaults.methodhandle_class = mono_class_from_name (
1468 mono_defaults.corlib, "System", "RuntimeMethodHandle");
1469 g_assert (mono_defaults.methodhandle_class != 0);
1471 mono_defaults.fieldhandle_class = mono_class_from_name (
1472 mono_defaults.corlib, "System", "RuntimeFieldHandle");
1473 g_assert (mono_defaults.fieldhandle_class != 0);
1475 mono_defaults.systemtype_class = mono_class_from_name (
1476 mono_defaults.corlib, "System", "Type");
1477 g_assert (mono_defaults.systemtype_class != 0);
1479 mono_defaults.monotype_class = mono_class_from_name (
1480 mono_defaults.corlib, "System", "MonoType");
1481 g_assert (mono_defaults.monotype_class != 0);
1483 mono_defaults.exception_class = mono_class_from_name (
1484 mono_defaults.corlib, "System", "Exception");
1485 g_assert (mono_defaults.exception_class != 0);
1487 mono_defaults.threadabortexception_class = mono_class_from_name (
1488 mono_defaults.corlib, "System.Threading", "ThreadAbortException");
1489 g_assert (mono_defaults.threadabortexception_class != 0);
1491 mono_defaults.thread_class = mono_class_from_name (
1492 mono_defaults.corlib, "System.Threading", "Thread");
1493 g_assert (mono_defaults.thread_class != 0);
1495 mono_defaults.internal_thread_class = mono_class_from_name (
1496 mono_defaults.corlib, "System.Threading", "InternalThread");
1497 if (!mono_defaults.internal_thread_class) {
1498 /* This can happen with an old mscorlib */
1499 fprintf (stderr, "Corlib too old for this runtime.\n");
1500 fprintf (stderr, "Loaded from: %s\n",
1501 mono_defaults.corlib? mono_image_get_filename (mono_defaults.corlib): "unknown");
1505 mono_defaults.appdomain_class = mono_class_from_name (
1506 mono_defaults.corlib, "System", "AppDomain");
1507 g_assert (mono_defaults.appdomain_class != 0);
1509 mono_defaults.transparent_proxy_class = mono_class_from_name (
1510 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "TransparentProxy");
1511 g_assert (mono_defaults.transparent_proxy_class != 0);
1513 mono_defaults.real_proxy_class = mono_class_from_name (
1514 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "RealProxy");
1515 g_assert (mono_defaults.real_proxy_class != 0);
1517 mono_defaults.mono_method_message_class = mono_class_from_name (
1518 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", "MonoMethodMessage");
1519 g_assert (mono_defaults.mono_method_message_class != 0);
1521 mono_defaults.field_info_class = mono_class_from_name (
1522 mono_defaults.corlib, "System.Reflection", "FieldInfo");
1523 g_assert (mono_defaults.field_info_class != 0);
1525 mono_defaults.method_info_class = mono_class_from_name (
1526 mono_defaults.corlib, "System.Reflection", "MethodInfo");
1527 g_assert (mono_defaults.method_info_class != 0);
1529 mono_defaults.stringbuilder_class = mono_class_from_name (
1530 mono_defaults.corlib, "System.Text", "StringBuilder");
1531 g_assert (mono_defaults.stringbuilder_class != 0);
1533 mono_defaults.math_class = mono_class_from_name (
1534 mono_defaults.corlib, "System", "Math");
1535 g_assert (mono_defaults.math_class != 0);
1537 mono_defaults.stack_frame_class = mono_class_from_name (
1538 mono_defaults.corlib, "System.Diagnostics", "StackFrame");
1539 g_assert (mono_defaults.stack_frame_class != 0);
1541 mono_defaults.stack_trace_class = mono_class_from_name (
1542 mono_defaults.corlib, "System.Diagnostics", "StackTrace");
1543 g_assert (mono_defaults.stack_trace_class != 0);
1545 mono_defaults.marshal_class = mono_class_from_name (
1546 mono_defaults.corlib, "System.Runtime.InteropServices", "Marshal");
1547 g_assert (mono_defaults.marshal_class != 0);
1549 mono_defaults.iserializeable_class = mono_class_from_name (
1550 mono_defaults.corlib, "System.Runtime.Serialization", "ISerializable");
1551 g_assert (mono_defaults.iserializeable_class != 0);
1553 mono_defaults.serializationinfo_class = mono_class_from_name (
1554 mono_defaults.corlib, "System.Runtime.Serialization", "SerializationInfo");
1555 g_assert (mono_defaults.serializationinfo_class != 0);
1557 mono_defaults.streamingcontext_class = mono_class_from_name (
1558 mono_defaults.corlib, "System.Runtime.Serialization", "StreamingContext");
1559 g_assert (mono_defaults.streamingcontext_class != 0);
1561 mono_defaults.typed_reference_class = mono_class_from_name (
1562 mono_defaults.corlib, "System", "TypedReference");
1563 g_assert (mono_defaults.typed_reference_class != 0);
1565 mono_defaults.argumenthandle_class = mono_class_from_name (
1566 mono_defaults.corlib, "System", "RuntimeArgumentHandle");
1567 g_assert (mono_defaults.argumenthandle_class != 0);
1569 mono_defaults.marshalbyrefobject_class = mono_class_from_name (
1570 mono_defaults.corlib, "System", "MarshalByRefObject");
1571 g_assert (mono_defaults.marshalbyrefobject_class != 0);
1573 mono_defaults.monitor_class = mono_class_from_name (
1574 mono_defaults.corlib, "System.Threading", "Monitor");
1575 g_assert (mono_defaults.monitor_class != 0);
1577 mono_defaults.iremotingtypeinfo_class = mono_class_from_name (
1578 mono_defaults.corlib, "System.Runtime.Remoting", "IRemotingTypeInfo");
1579 g_assert (mono_defaults.iremotingtypeinfo_class != 0);
1581 mono_defaults.runtimesecurityframe_class = mono_class_from_name (
1582 mono_defaults.corlib, "System.Security", "RuntimeSecurityFrame");
1584 mono_defaults.executioncontext_class = mono_class_from_name (
1585 mono_defaults.corlib, "System.Threading", "ExecutionContext");
1587 mono_defaults.internals_visible_class = mono_class_from_name (
1588 mono_defaults.corlib, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute");
1590 mono_defaults.critical_finalizer_object = mono_class_from_name (
1591 mono_defaults.corlib, "System.Runtime.ConstrainedExecution", "CriticalFinalizerObject");
1594 * mscorlib needs a little help, only now it can load its friends list (after we have
1595 * loaded the InternalsVisibleToAttribute), load it now
1597 mono_assembly_load_friends (ass);
1599 mono_defaults.safehandle_class = mono_class_from_name (
1600 mono_defaults.corlib, "System.Runtime.InteropServices", "SafeHandle");
1602 mono_defaults.handleref_class = mono_class_from_name (
1603 mono_defaults.corlib, "System.Runtime.InteropServices", "HandleRef");
1605 mono_defaults.attribute_class = mono_class_from_name (
1606 mono_defaults.corlib, "System", "Attribute");
1608 mono_defaults.customattribute_data_class = mono_class_from_name (
1609 mono_defaults.corlib, "System.Reflection", "CustomAttributeData");
1611 /* these are initialized lazily when COM features are used */
1612 mono_defaults.variant_class = NULL;
1613 mono_defaults.com_object_class = NULL;
1614 mono_defaults.com_interop_proxy_class = NULL;
1615 mono_defaults.iunknown_class = NULL;
1616 mono_defaults.idispatch_class = NULL;
1619 * Note that mono_defaults.generic_*_class is only non-NULL if we're
1620 * using the 2.0 corlib.
1622 mono_class_init (mono_defaults.array_class);
1623 mono_defaults.generic_nullable_class = mono_class_from_name (
1624 mono_defaults.corlib, "System", "Nullable`1");
1625 mono_defaults.generic_ilist_class = mono_class_from_name (
1626 mono_defaults.corlib, "System.Collections.Generic", "IList`1");
1628 domain->friendly_name = g_path_get_basename (filename);
1630 _mono_debug_init_corlib (domain);
1638 * Creates the initial application domain and initializes the mono_defaults
1640 * This function is guaranteed to not run any IL code.
1641 * The runtime is initialized using the default runtime version.
1643 * Returns: the initial domain.
1646 mono_init (const char *domain_name)
1648 return mono_init_internal (domain_name, NULL, DEFAULT_RUNTIME_VERSION);
1652 * mono_init_from_assembly:
1653 * @domain_name: name to give to the initial domain
1654 * @filename: filename to load on startup
1656 * Used by the runtime, users should use mono_jit_init instead.
1658 * Creates the initial application domain and initializes the mono_defaults
1660 * This function is guaranteed to not run any IL code.
1661 * The runtime is initialized using the runtime version required by the
1662 * provided executable. The version is determined by looking at the exe
1663 * configuration file and the version PE field)
1665 * Returns: the initial domain.
1668 mono_init_from_assembly (const char *domain_name, const char *filename)
1670 return mono_init_internal (domain_name, filename, NULL);
1674 * mono_init_version:
1676 * Used by the runtime, users should use mono_jit_init instead.
1678 * Creates the initial application domain and initializes the mono_defaults
1681 * This function is guaranteed to not run any IL code.
1682 * The runtime is initialized using the provided rutime version.
1684 * Returns: the initial domain.
1687 mono_init_version (const char *domain_name, const char *version)
1689 return mono_init_internal (domain_name, NULL, version);
1693 * mono_init_com_types:
1695 * Initializes all types needed for COM Interop in mono_defaults structure.
1698 mono_init_com_types (void)
1700 static gboolean initialized = FALSE;
1705 /* FIXME: do I need some threading protection here */
1707 g_assert (mono_defaults.corlib);
1709 mono_defaults.variant_class = mono_class_from_name (
1710 mono_defaults.corlib, "System", "Variant");
1711 g_assert (mono_defaults.variant_class != 0);
1713 mono_defaults.com_object_class = mono_class_from_name (
1714 mono_defaults.corlib, "System", "__ComObject");
1715 g_assert (mono_defaults.com_object_class != 0);
1717 mono_defaults.com_interop_proxy_class = mono_class_from_name (
1718 mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
1719 g_assert (mono_defaults.com_interop_proxy_class != 0);
1721 mono_defaults.iunknown_class = mono_class_from_name (
1722 mono_defaults.corlib, "Mono.Interop", "IUnknown");
1723 g_assert (mono_defaults.iunknown_class != 0);
1725 mono_defaults.idispatch_class = mono_class_from_name (
1726 mono_defaults.corlib, "Mono.Interop", "IDispatch");
1727 g_assert (mono_defaults.idispatch_class != 0);
1735 * Cleans up all metadata modules.
1740 mono_close_exe_image ();
1742 mono_defaults.corlib = NULL;
1744 mono_config_cleanup ();
1745 mono_loader_cleanup ();
1746 mono_classes_cleanup ();
1747 mono_assemblies_cleanup ();
1748 mono_images_cleanup ();
1749 mono_debug_cleanup ();
1750 mono_metadata_cleanup ();
1752 TlsFree (appdomain_thread_id);
1753 DeleteCriticalSection (&appdomains_mutex);
1756 * This should be called last as TlsGetValue ()/TlsSetValue () can be called during
1765 mono_close_exe_image (void)
1768 mono_image_close (exe_image);
1772 * mono_get_root_domain:
1774 * The root AppDomain is the initial domain created by the runtime when it is
1775 * initialized. Programs execute on this AppDomain, but can create new ones
1776 * later. Currently there is no unmanaged API to create new AppDomains, this
1777 * must be done from managed code.
1779 * Returns: the root appdomain, to obtain the current domain, use mono_domain_get ()
1782 mono_get_root_domain (void)
1784 return mono_root_domain;
1790 * Returns: the current domain, to obtain the root domain use
1791 * mono_get_root_domain().
1796 return GET_APPDOMAIN ();
1800 mono_domain_unset (void)
1802 SET_APPDOMAIN (NULL);
1806 mono_domain_set_internal_with_options (MonoDomain *domain, gboolean migrate_exception)
1808 MonoInternalThread *thread;
1810 if (mono_domain_get () == domain)
1813 SET_APPDOMAIN (domain);
1814 SET_APPCONTEXT (domain->default_context);
1816 if (migrate_exception) {
1817 thread = mono_thread_internal_current ();
1818 if (!thread->abort_exc)
1821 g_assert (thread->abort_exc->object.vtable->domain != domain);
1822 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
1823 g_assert (thread->abort_exc->object.vtable->domain == domain);
1828 * mono_domain_set_internal:
1829 * @domain: the new domain
1831 * Sets the current domain to @domain.
1834 mono_domain_set_internal (MonoDomain *domain)
1836 mono_domain_set_internal_with_options (domain, TRUE);
1840 mono_domain_foreach (MonoDomainFunc func, gpointer user_data)
1846 * Create a copy of the data to avoid calling the user callback
1847 * inside the lock because that could lead to deadlocks.
1848 * We can do this because this function is not perf. critical.
1850 mono_appdomains_lock ();
1851 size = appdomain_list_size;
1852 copy = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1853 memcpy (copy, appdomains_list, appdomain_list_size * sizeof (void*));
1854 mono_appdomains_unlock ();
1856 for (i = 0; i < size; ++i) {
1858 func (copy [i], user_data);
1861 mono_gc_free_fixed (copy);
1865 * mono_domain_assembly_open:
1866 * @domain: the application domain
1867 * @name: file name of the assembly
1869 * fixme: maybe we should integrate this with mono_assembly_open ??
1872 mono_domain_assembly_open (MonoDomain *domain, const char *name)
1874 MonoDomain *current;
1878 mono_domain_assemblies_lock (domain);
1879 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1881 if (strcmp (name, ass->aname.name) == 0) {
1882 mono_domain_assemblies_unlock (domain);
1886 mono_domain_assemblies_unlock (domain);
1888 if (domain != mono_domain_get ()) {
1889 current = mono_domain_get ();
1891 mono_domain_set (domain, FALSE);
1892 ass = mono_assembly_open (name, NULL);
1893 mono_domain_set (current, FALSE);
1895 ass = mono_assembly_open (name, NULL);
1902 free_slist (gpointer key, gpointer value, gpointer user_data)
1904 g_slist_free (value);
1908 unregister_vtable_reflection_type (MonoVTable *vtable)
1910 MonoObject *type = vtable->type;
1912 if (type->vtable->klass != mono_defaults.monotype_class)
1913 MONO_GC_UNREGISTER_ROOT_IF_MOVING (vtable->type);
1917 mono_domain_free (MonoDomain *domain, gboolean force)
1919 int code_size, code_alloc;
1921 if ((domain == mono_root_domain) && !force) {
1922 g_warning ("cant unload root domain");
1926 if (mono_dont_free_domains)
1929 mono_profiler_appdomain_event (domain, MONO_PROFILE_START_UNLOAD);
1931 mono_debug_domain_unload (domain);
1933 mono_appdomains_lock ();
1934 appdomains_list [domain->domain_id] = NULL;
1935 mono_appdomains_unlock ();
1937 /* must do this early as it accesses fields and types */
1938 if (domain->special_static_fields) {
1939 mono_alloc_special_static_data_free (domain->special_static_fields);
1940 g_hash_table_destroy (domain->special_static_fields);
1941 domain->special_static_fields = NULL;
1945 * We must destroy all these hash tables here because they
1946 * contain references to managed objects belonging to the
1947 * domain. Once we let the GC clear the domain there must be
1948 * no more such references, or we'll crash if a collection
1951 mono_g_hash_table_destroy (domain->ldstr_table);
1952 domain->ldstr_table = NULL;
1954 mono_g_hash_table_destroy (domain->env);
1957 mono_reflection_cleanup_domain (domain);
1959 if (domain->type_hash) {
1960 mono_g_hash_table_destroy (domain->type_hash);
1961 domain->type_hash = NULL;
1963 if (domain->type_init_exception_hash) {
1964 mono_g_hash_table_destroy (domain->type_init_exception_hash);
1965 domain->type_init_exception_hash = NULL;
1968 if (domain->class_vtable_array) {
1970 for (i = 0; i < domain->class_vtable_array->len; ++i)
1971 unregister_vtable_reflection_type (g_ptr_array_index (domain->class_vtable_array, i));
1974 /* This needs to be done before closing assemblies */
1975 mono_gc_clear_domain (domain);
1977 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1978 MonoAssembly *ass = tmp->data;
1979 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);
1980 if (!mono_assembly_close_except_image_pools (ass))
1984 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1985 MonoAssembly *ass = tmp->data;
1987 mono_assembly_close_finish (ass);
1989 g_slist_free (domain->domain_assemblies);
1990 domain->domain_assemblies = NULL;
1993 * Send this after the assemblies have been unloaded and the domain is still in a
1996 mono_profiler_appdomain_event (domain, MONO_PROFILE_END_UNLOAD);
1998 if (free_domain_hook)
1999 free_domain_hook (domain);
2001 /* FIXME: free delegate_hash_table when it's used */
2002 if (domain->search_path) {
2003 g_strfreev (domain->search_path);
2004 domain->search_path = NULL;
2006 domain->create_proxy_for_type_method = NULL;
2007 domain->private_invoke_method = NULL;
2008 domain->default_context = NULL;
2009 domain->out_of_memory_ex = NULL;
2010 domain->null_reference_ex = NULL;
2011 domain->stack_overflow_ex = NULL;
2012 domain->ephemeron_tombstone = NULL;
2013 domain->entry_assembly = NULL;
2015 g_free (domain->friendly_name);
2016 domain->friendly_name = NULL;
2017 g_ptr_array_free (domain->class_vtable_array, TRUE);
2018 domain->class_vtable_array = NULL;
2019 g_hash_table_destroy (domain->proxy_vtable_hash);
2020 domain->proxy_vtable_hash = NULL;
2021 if (domain->static_data_array) {
2022 mono_gc_free_fixed (domain->static_data_array);
2023 domain->static_data_array = NULL;
2025 mono_internal_hash_table_destroy (&domain->jit_code_hash);
2028 * There might still be jit info tables of this domain which
2029 * are not freed. Since the domain cannot be in use anymore,
2030 * this will free them.
2032 mono_thread_hazardous_try_free_all ();
2033 g_assert (domain->num_jit_info_tables == 1);
2034 jit_info_table_free (domain->jit_info_table);
2035 domain->jit_info_table = NULL;
2036 g_assert (!domain->jit_info_free_queue);
2038 /* collect statistics */
2039 code_alloc = mono_code_manager_size (domain->code_mp, &code_size);
2040 total_domain_code_alloc += code_alloc;
2041 max_domain_code_alloc = MAX (max_domain_code_alloc, code_alloc);
2042 max_domain_code_size = MAX (max_domain_code_size, code_size);
2044 #ifdef DEBUG_DOMAIN_UNLOAD
2045 mono_mempool_invalidate (domain->mp);
2046 mono_code_manager_invalidate (domain->code_mp);
2048 mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (domain->mp);
2049 mono_mempool_destroy (domain->mp);
2051 mono_code_manager_destroy (domain->code_mp);
2052 domain->code_mp = NULL;
2055 g_hash_table_destroy (domain->finalizable_objects_hash);
2056 domain->finalizable_objects_hash = NULL;
2057 if (domain->track_resurrection_objects_hash) {
2058 g_hash_table_foreach (domain->track_resurrection_objects_hash, free_slist, NULL);
2059 g_hash_table_destroy (domain->track_resurrection_objects_hash);
2061 if (domain->track_resurrection_handles_hash)
2062 g_hash_table_destroy (domain->track_resurrection_handles_hash);
2063 if (domain->method_rgctx_hash) {
2064 g_hash_table_destroy (domain->method_rgctx_hash);
2065 domain->method_rgctx_hash = NULL;
2067 if (domain->generic_virtual_cases) {
2068 g_hash_table_destroy (domain->generic_virtual_cases);
2069 domain->generic_virtual_cases = NULL;
2072 DeleteCriticalSection (&domain->finalizable_objects_hash_lock);
2073 DeleteCriticalSection (&domain->assemblies_lock);
2074 DeleteCriticalSection (&domain->jit_code_hash_lock);
2075 DeleteCriticalSection (&domain->lock);
2076 domain->setup = NULL;
2078 mono_gc_deregister_root ((char*)&(domain->MONO_DOMAIN_FIRST_GC_TRACKED));
2080 /* FIXME: anything else required ? */
2082 mono_gc_free_fixed (domain);
2084 mono_perfcounters->loader_appdomains--;
2086 if ((domain == mono_root_domain))
2087 mono_root_domain = NULL;
2091 * mono_domain_get_id:
2094 * Returns: the a domain for a specific domain id.
2097 mono_domain_get_by_id (gint32 domainid)
2099 MonoDomain * domain;
2101 mono_appdomains_lock ();
2102 if (domainid < appdomain_list_size)
2103 domain = appdomains_list [domainid];
2106 mono_appdomains_unlock ();
2112 mono_domain_get_id (MonoDomain *domain)
2114 return domain->domain_id;
2118 * mono_domain_alloc:
2120 * LOCKING: Acquires the domain lock.
2123 mono_domain_alloc (MonoDomain *domain, guint size)
2127 mono_domain_lock (domain);
2128 mono_perfcounters->loader_bytes += size;
2129 res = mono_mempool_alloc (domain->mp, size);
2130 mono_domain_unlock (domain);
2136 * mono_domain_alloc0:
2138 * LOCKING: Acquires the domain lock.
2141 mono_domain_alloc0 (MonoDomain *domain, guint size)
2145 mono_domain_lock (domain);
2146 mono_perfcounters->loader_bytes += size;
2147 res = mono_mempool_alloc0 (domain->mp, size);
2148 mono_domain_unlock (domain);
2154 * mono_domain_code_reserve:
2156 * LOCKING: Acquires the domain lock.
2159 mono_domain_code_reserve (MonoDomain *domain, int size)
2163 mono_domain_lock (domain);
2164 res = mono_code_manager_reserve (domain->code_mp, size);
2165 mono_domain_unlock (domain);
2171 * mono_domain_code_reserve_align:
2173 * LOCKING: Acquires the domain lock.
2176 mono_domain_code_reserve_align (MonoDomain *domain, int size, int alignment)
2180 mono_domain_lock (domain);
2181 res = mono_code_manager_reserve_align (domain->code_mp, size, alignment);
2182 mono_domain_unlock (domain);
2188 * mono_domain_code_commit:
2190 * LOCKING: Acquires the domain lock.
2193 mono_domain_code_commit (MonoDomain *domain, void *data, int size, int newsize)
2195 mono_domain_lock (domain);
2196 mono_code_manager_commit (domain->code_mp, data, size, newsize);
2197 mono_domain_unlock (domain);
2200 #if defined(__native_client_codegen__) && defined(__native_client__)
2202 * Given the temporary buffer (allocated by mono_domain_code_reserve) into which
2203 * we are generating code, return a pointer to the destination in the dynamic
2204 * code segment into which the code will be copied when mono_domain_code_commit
2206 * LOCKING: Acquires the domain lock.
2209 nacl_domain_get_code_dest (MonoDomain *domain, void *data)
2212 mono_domain_lock (domain);
2213 dest = nacl_code_manager_get_code_dest (domain->code_mp, data);
2214 mono_domain_unlock (domain);
2219 * Convenience function which calls mono_domain_code_commit to validate and copy
2220 * the code. The caller sets *buf_base and *buf_size to the start and size of
2221 * the buffer (allocated by mono_domain_code_reserve), and *code_end to the byte
2222 * after the last instruction byte. On return, *buf_base will point to the start
2223 * of the copied in the code segment, and *code_end will point after the end of
2227 nacl_domain_code_validate (MonoDomain *domain, guint8 **buf_base, int buf_size, guint8 **code_end)
2229 guint8 *tmp = nacl_domain_get_code_dest (domain, *buf_base);
2230 mono_domain_code_commit (domain, *buf_base, buf_size, *code_end - *buf_base);
2231 *code_end = tmp + (*code_end - *buf_base);
2237 /* no-op versions of Native Client functions */
2240 nacl_domain_get_code_dest (MonoDomain *domain, void *data)
2246 nacl_domain_code_validate (MonoDomain *domain, guint8 **buf_base, int buf_size, guint8 **code_end)
2253 * mono_domain_code_foreach:
2254 * Iterate over the code thunks of the code manager of @domain.
2256 * The @func callback MUST not take any locks. If it really needs to, it must respect
2257 * the locking rules of the runtime: http://www.mono-project.com/Mono:Runtime:Documentation:ThreadSafety
2258 * LOCKING: Acquires the domain lock.
2262 mono_domain_code_foreach (MonoDomain *domain, MonoCodeManagerFunc func, void *user_data)
2264 mono_domain_lock (domain);
2265 mono_code_manager_foreach (domain->code_mp, func, user_data);
2266 mono_domain_unlock (domain);
2271 mono_context_set (MonoAppContext * new_context)
2273 SET_APPCONTEXT (new_context);
2277 mono_context_get (void)
2279 return GET_APPCONTEXT ();
2282 /* LOCKING: the caller holds the lock for this domain */
2284 mono_domain_add_class_static_data (MonoDomain *domain, MonoClass *klass, gpointer data, guint32 *bitmap)
2286 /* The first entry in the array is the index of the next free slot
2287 * and the total size of the array
2290 if (domain->static_data_array) {
2291 int size = GPOINTER_TO_INT (domain->static_data_array [1]);
2292 next = GPOINTER_TO_INT (domain->static_data_array [0]);
2294 /* 'data' is allocated by alloc_fixed */
2295 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * (size * 2), MONO_GC_ROOT_DESCR_FOR_FIXED (size * 2));
2296 memcpy (new_array, domain->static_data_array, sizeof (gpointer) * size);
2298 new_array [1] = GINT_TO_POINTER (size);
2299 mono_gc_free_fixed (domain->static_data_array);
2300 domain->static_data_array = new_array;
2304 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * size, MONO_GC_ROOT_DESCR_FOR_FIXED (size));
2306 new_array [0] = GINT_TO_POINTER (next);
2307 new_array [1] = GINT_TO_POINTER (size);
2308 domain->static_data_array = new_array;
2310 domain->static_data_array [next++] = data;
2311 domain->static_data_array [0] = GINT_TO_POINTER (next);
2315 mono_get_corlib (void)
2317 return mono_defaults.corlib;
2321 mono_get_object_class (void)
2323 return mono_defaults.object_class;
2327 mono_get_byte_class (void)
2329 return mono_defaults.byte_class;
2333 mono_get_void_class (void)
2335 return mono_defaults.void_class;
2339 mono_get_boolean_class (void)
2341 return mono_defaults.boolean_class;
2345 mono_get_sbyte_class (void)
2347 return mono_defaults.sbyte_class;
2351 mono_get_int16_class (void)
2353 return mono_defaults.int16_class;
2357 mono_get_uint16_class (void)
2359 return mono_defaults.uint16_class;
2363 mono_get_int32_class (void)
2365 return mono_defaults.int32_class;
2369 mono_get_uint32_class (void)
2371 return mono_defaults.uint32_class;
2375 mono_get_intptr_class (void)
2377 return mono_defaults.int_class;
2381 mono_get_uintptr_class (void)
2383 return mono_defaults.uint_class;
2387 mono_get_int64_class (void)
2389 return mono_defaults.int64_class;
2393 mono_get_uint64_class (void)
2395 return mono_defaults.uint64_class;
2399 mono_get_single_class (void)
2401 return mono_defaults.single_class;
2405 mono_get_double_class (void)
2407 return mono_defaults.double_class;
2411 mono_get_char_class (void)
2413 return mono_defaults.char_class;
2417 mono_get_string_class (void)
2419 return mono_defaults.string_class;
2423 mono_get_enum_class (void)
2425 return mono_defaults.enum_class;
2429 mono_get_array_class (void)
2431 return mono_defaults.array_class;
2435 mono_get_thread_class (void)
2437 return mono_defaults.thread_class;
2441 mono_get_exception_class (void)
2443 return mono_defaults.exception_class;
2447 static char* get_attribute_value (const gchar **attribute_names,
2448 const gchar **attribute_values,
2449 const char *att_name)
2452 for (n=0; attribute_names[n] != NULL; n++) {
2453 if (strcmp (attribute_names[n], att_name) == 0)
2454 return g_strdup (attribute_values[n]);
2459 static void start_element (GMarkupParseContext *context,
2460 const gchar *element_name,
2461 const gchar **attribute_names,
2462 const gchar **attribute_values,
2466 AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2468 if (strcmp (element_name, "configuration") == 0) {
2469 app_config->configuration_count++;
2472 if (strcmp (element_name, "startup") == 0) {
2473 app_config->startup_count++;
2477 if (app_config->configuration_count != 1 || app_config->startup_count != 1)
2480 if (strcmp (element_name, "requiredRuntime") == 0) {
2481 app_config->required_runtime = get_attribute_value (attribute_names, attribute_values, "version");
2482 } else if (strcmp (element_name, "supportedRuntime") == 0) {
2483 char *version = get_attribute_value (attribute_names, attribute_values, "version");
2484 app_config->supported_runtimes = g_slist_append (app_config->supported_runtimes, version);
2488 static void end_element (GMarkupParseContext *context,
2489 const gchar *element_name,
2493 AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2495 if (strcmp (element_name, "configuration") == 0) {
2496 app_config->configuration_count--;
2497 } else if (strcmp (element_name, "startup") == 0) {
2498 app_config->startup_count--;
2502 static const GMarkupParser
2511 static AppConfigInfo *
2512 app_config_parse (const char *exe_filename)
2514 AppConfigInfo *app_config;
2515 GMarkupParseContext *context;
2518 const char *bundled_config;
2519 char *config_filename;
2521 bundled_config = mono_config_string_for_assembly_file (exe_filename);
2523 if (bundled_config) {
2524 text = g_strdup (bundled_config);
2525 len = strlen (text);
2527 config_filename = g_strconcat (exe_filename, ".config", NULL);
2529 if (!g_file_get_contents (config_filename, &text, &len, NULL)) {
2530 g_free (config_filename);
2533 g_free (config_filename);
2536 app_config = g_new0 (AppConfigInfo, 1);
2538 context = g_markup_parse_context_new (&mono_parser, 0, app_config, NULL);
2539 if (g_markup_parse_context_parse (context, text, len, NULL)) {
2540 g_markup_parse_context_end_parse (context, NULL);
2542 g_markup_parse_context_free (context);
2548 app_config_free (AppConfigInfo* app_config)
2551 GSList *list = app_config->supported_runtimes;
2552 while (list != NULL) {
2553 rt = (char*)list->data;
2555 list = g_slist_next (list);
2557 g_slist_free (app_config->supported_runtimes);
2558 g_free (app_config->required_runtime);
2559 g_free (app_config);
2563 static const MonoRuntimeInfo*
2564 get_runtime_by_version (const char *version)
2567 int max = G_N_ELEMENTS (supported_runtimes);
2568 gboolean do_partial_match;
2574 vlen = strlen (version);
2575 if (vlen >= 4 && version [1] - '0' >= 4)
2576 do_partial_match = TRUE;
2578 do_partial_match = FALSE;
2580 for (n=0; n<max; n++) {
2581 if (do_partial_match && strncmp (version, supported_runtimes[n].runtime_version, vlen) == 0)
2582 return &supported_runtimes[n];
2583 if (strcmp (version, supported_runtimes[n].runtime_version) == 0)
2584 return &supported_runtimes[n];
2590 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes)
2592 AppConfigInfo* app_config;
2594 const MonoRuntimeInfo* runtime = NULL;
2595 MonoImage *image = NULL;
2597 app_config = app_config_parse (exe_file);
2599 if (app_config != NULL) {
2600 /* Check supportedRuntime elements, if none is supported, fail.
2601 * If there are no such elements, look for a requiredRuntime element.
2603 if (app_config->supported_runtimes != NULL) {
2605 GSList *list = app_config->supported_runtimes;
2606 while (list != NULL) {
2607 version = (char*) list->data;
2608 runtime = get_runtime_by_version (version);
2609 if (runtime != NULL)
2610 runtimes [n++] = runtime;
2611 list = g_slist_next (list);
2613 runtimes [n] = NULL;
2614 app_config_free (app_config);
2618 /* Check the requiredRuntime element. This is for 1.0 apps only. */
2619 if (app_config->required_runtime != NULL) {
2620 runtimes [0] = get_runtime_by_version (app_config->required_runtime);
2621 runtimes [1] = NULL;
2622 app_config_free (app_config);
2625 app_config_free (app_config);
2628 /* Look for a runtime with the exact version */
2629 image = mono_assembly_open_from_bundle (exe_file, NULL, FALSE);
2632 image = mono_image_open (exe_file, NULL);
2634 if (image == NULL) {
2635 /* The image is wrong or the file was not found. In this case return
2636 * a default runtime and leave to the initialization method the work of
2637 * reporting the error.
2639 runtimes [0] = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
2640 runtimes [1] = NULL;
2646 runtimes [0] = get_runtime_by_version (image->version);
2647 runtimes [1] = NULL;
2652 * mono_get_runtime_info:
2654 * Returns: the version of the current runtime instance.
2656 const MonoRuntimeInfo*
2657 mono_get_runtime_info (void)
2659 return current_runtime;
2663 mono_debugger_check_runtime_version (const char *filename)
2665 const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
2666 const MonoRuntimeInfo *rinfo;
2669 get_runtimes_from_exe (filename, &image, runtimes);
2670 rinfo = runtimes [0];
2673 return g_strdup_printf ("Cannot get runtime version from assembly `%s'", filename);
2675 if (rinfo != current_runtime)
2676 return g_strdup_printf ("The Mono Debugger is currently using the `%s' runtime, but "
2677 "the assembly `%s' requires version `%s'", current_runtime->runtime_version,
2678 filename, rinfo->runtime_version);
2684 * mono_framework_version:
2686 * Return the major version of the framework curently executing.
2689 mono_framework_version (void)
2691 return current_runtime->framework_version [0] - '0';