2010-03-30 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / metadata / domain.c
blobb6cf5c2289479417eb0380c93ea961c9e47a7aca
1 /*
2 * domain.c: MonoDomain functions
4 * Author:
5 * Dietmar Maurer (dietmar@ximian.com)
6 * Patrik Torstensson
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
12 #include <config.h>
13 #include <glib.h>
14 #include <string.h>
15 #include <sys/stat.h>
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;
48 /*
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
54 #endif
56 #ifdef HAVE_KW_THREAD
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 { \
64 tls_appdomain = x; \
65 } while (FALSE)
66 #else
67 #define SET_APPDOMAIN(x) do { \
68 tls_appdomain = x; \
69 TlsSetValue (appdomain_thread_id, x); \
70 } while (FALSE)
71 #endif
73 #else /* !HAVE_KW_THREAD */
75 #define GET_APPDOMAIN() ((MonoDomain *)TlsGetValue (appdomain_thread_id))
76 #define SET_APPDOMAIN(x) TlsSetValue (appdomain_thread_id, x);
78 #endif
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;
96 /* some statistics */
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
102 * aplication.
104 typedef struct {
105 GSList *supported_runtimes;
106 char *required_runtime;
107 int configuration_count;
108 int startup_count;
109 } AppConfigInfo;
112 * AotModuleInfo: Contains information about AOT modules.
114 typedef struct {
115 MonoImage *image;
116 gpointer start, end;
117 } AotModuleInfo;
119 static const MonoRuntimeInfo *current_runtime = NULL;
121 static MonoJitInfoFindInAot jit_info_find_in_aot_func = NULL;
124 * Contains information about AOT loaded code.
126 static MonoAotModuleInfoTable *aot_modules = NULL;
128 /* This is the list of runtime versions supported by this JIT.
130 static const MonoRuntimeInfo supported_runtimes[] = {
131 {"v2.0.50215","2.0", { {2,0,0,0}, {8,0,0,0} } },
132 {"v2.0.50727","2.0", { {2,0,0,0}, {8,0,0,0} } },
133 {"v4.0.21006","4.0", { {4,0,0,0}, {10,0,0,0} } },
134 {"v4.0.30128","4.0", { {4,0,0,0}, {10,0,0,0} } },
135 {"moonlight", "2.1", { {2,0,5,0}, {9,0,0,0} } },
139 /* The stable runtime version */
140 #define DEFAULT_RUNTIME_VERSION "v2.0.50727"
142 /* Callbacks installed by the JIT */
143 static MonoCreateDomainFunc create_domain_hook;
144 static MonoFreeDomainFunc free_domain_hook;
146 /* This is intentionally not in the header file, so people don't misuse it. */
147 extern void _mono_debug_init_corlib (MonoDomain *domain);
149 static void
150 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes);
152 static const MonoRuntimeInfo*
153 get_runtime_by_version (const char *version);
155 static MonoImage*
156 mono_jit_info_find_aot_module (guint8* addr);
158 guint32
159 mono_domain_get_tls_key (void)
161 #ifdef NO_TLS_SET_VALUE
162 g_assert_not_reached ();
163 return 0;
164 #else
165 return appdomain_thread_id;
166 #endif
169 gint32
170 mono_domain_get_tls_offset (void)
172 int offset = -1;
173 MONO_THREAD_VAR_OFFSET (tls_appdomain, offset);
174 /* __asm ("jmp 1f; .section writetext, \"awx\"; 1: movl $tls_appdomain@ntpoff, %0; jmp 2f; .previous; 2:"
175 : "=r" (offset));*/
176 return offset;
179 #define JIT_INFO_TABLE_FILL_RATIO_NOM 3
180 #define JIT_INFO_TABLE_FILL_RATIO_DENOM 4
181 #define JIT_INFO_TABLE_FILLED_NUM_ELEMENTS (MONO_JIT_INFO_TABLE_CHUNK_SIZE * JIT_INFO_TABLE_FILL_RATIO_NOM / JIT_INFO_TABLE_FILL_RATIO_DENOM)
183 #define JIT_INFO_TABLE_LOW_WATERMARK(n) ((n) / 2)
184 #define JIT_INFO_TABLE_HIGH_WATERMARK(n) ((n) * 5 / 6)
186 #define JIT_INFO_TOMBSTONE_MARKER ((MonoMethod*)NULL)
187 #define IS_JIT_INFO_TOMBSTONE(ji) ((ji)->method == JIT_INFO_TOMBSTONE_MARKER)
189 #define JIT_INFO_TABLE_HAZARD_INDEX 0
190 #define JIT_INFO_HAZARD_INDEX 1
192 static int
193 jit_info_table_num_elements (MonoJitInfoTable *table)
195 int i;
196 int num_elements = 0;
198 for (i = 0; i < table->num_chunks; ++i) {
199 MonoJitInfoTableChunk *chunk = table->chunks [i];
200 int chunk_num_elements = chunk->num_elements;
201 int j;
203 for (j = 0; j < chunk_num_elements; ++j) {
204 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j]))
205 ++num_elements;
209 return num_elements;
212 static MonoJitInfoTableChunk*
213 jit_info_table_new_chunk (void)
215 MonoJitInfoTableChunk *chunk = g_new0 (MonoJitInfoTableChunk, 1);
216 chunk->refcount = 1;
218 return chunk;
221 static MonoJitInfoTable *
222 jit_info_table_new (MonoDomain *domain)
224 MonoJitInfoTable *table = g_malloc0 (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*));
226 table->domain = domain;
227 table->num_chunks = 1;
228 table->chunks [0] = jit_info_table_new_chunk ();
230 return table;
233 static void
234 jit_info_table_free (MonoJitInfoTable *table)
236 int i;
237 int num_chunks = table->num_chunks;
238 MonoDomain *domain = table->domain;
240 mono_domain_lock (domain);
242 table->domain->num_jit_info_tables--;
243 if (table->domain->num_jit_info_tables <= 1) {
244 GSList *list;
246 for (list = table->domain->jit_info_free_queue; list; list = list->next)
247 g_free (list->data);
249 g_slist_free (table->domain->jit_info_free_queue);
250 table->domain->jit_info_free_queue = NULL;
253 /* At this point we assume that there are no other threads
254 still accessing the table, so we don't have to worry about
255 hazardous pointers. */
257 for (i = 0; i < num_chunks; ++i) {
258 MonoJitInfoTableChunk *chunk = table->chunks [i];
259 int num_elements;
260 int j;
262 if (--chunk->refcount > 0)
263 continue;
265 num_elements = chunk->num_elements;
266 for (j = 0; j < num_elements; ++j) {
267 MonoJitInfo *ji = chunk->data [j];
269 if (IS_JIT_INFO_TOMBSTONE (ji))
270 g_free (ji);
273 g_free (chunk);
276 mono_domain_unlock (domain);
278 g_free (table);
281 /* Can be called with hp==NULL, in which case it acts as an ordinary
282 pointer fetch. It's used that way indirectly from
283 mono_jit_info_table_add(), which doesn't have to care about hazards
284 because it holds the respective domain lock. */
285 static gpointer
286 get_hazardous_pointer (gpointer volatile *pp, MonoThreadHazardPointers *hp, int hazard_index)
288 gpointer p;
290 for (;;) {
291 /* Get the pointer */
292 p = *pp;
293 /* If we don't have hazard pointers just return the
294 pointer. */
295 if (!hp)
296 return p;
297 /* Make it hazardous */
298 mono_hazard_pointer_set (hp, hazard_index, p);
299 /* Check that it's still the same. If not, try
300 again. */
301 if (*pp != p) {
302 mono_hazard_pointer_clear (hp, hazard_index);
303 continue;
305 break;
308 return p;
311 /* The jit_info_table is sorted in ascending order by the end
312 * addresses of the compiled methods. The reason why we have to do
313 * this is that once we introduce tombstones, it becomes possible for
314 * code ranges to overlap, and if we sort by code start and insert at
315 * the back of the table, we cannot guarantee that we won't overlook
316 * an entry.
318 * There are actually two possible ways to do the sorting and
319 * inserting which work with our lock-free mechanism:
321 * 1. Sort by start address and insert at the front. When looking for
322 * an entry, find the last one with a start address lower than the one
323 * you're looking for, then work your way to the front of the table.
325 * 2. Sort by end address and insert at the back. When looking for an
326 * entry, find the first one with an end address higher than the one
327 * you're looking for, then work your way to the end of the table.
329 * We chose the latter out of convenience.
331 static int
332 jit_info_table_index (MonoJitInfoTable *table, gint8 *addr)
334 int left = 0, right = table->num_chunks;
336 g_assert (left < right);
338 do {
339 int pos = (left + right) / 2;
340 MonoJitInfoTableChunk *chunk = table->chunks [pos];
342 if (addr < chunk->last_code_end)
343 right = pos;
344 else
345 left = pos + 1;
346 } while (left < right);
347 g_assert (left == right);
349 if (left >= table->num_chunks)
350 return table->num_chunks - 1;
351 return left;
354 static int
355 jit_info_table_chunk_index (MonoJitInfoTableChunk *chunk, MonoThreadHazardPointers *hp, gint8 *addr)
357 int left = 0, right = chunk->num_elements;
359 while (left < right) {
360 int pos = (left + right) / 2;
361 MonoJitInfo *ji = get_hazardous_pointer((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
362 gint8 *code_end = (gint8*)ji->code_start + ji->code_size;
364 if (addr < code_end)
365 right = pos;
366 else
367 left = pos + 1;
369 g_assert (left == right);
371 return left;
374 MonoJitInfo*
375 mono_jit_info_table_find (MonoDomain *domain, char *addr)
377 MonoJitInfoTable *table;
378 MonoJitInfo *ji;
379 int chunk_pos, pos;
380 MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
381 MonoImage *image;
383 ++mono_stats.jit_info_table_lookup_count;
385 /* First we have to get the domain's jit_info_table. This is
386 complicated by the fact that a writer might substitute a
387 new table and free the old one. What the writer guarantees
388 us is that it looks at the hazard pointers after it has
389 changed the jit_info_table pointer. So, if we guard the
390 table by a hazard pointer and make sure that the pointer is
391 still there after we've made it hazardous, we don't have to
392 worry about the writer freeing the table. */
393 table = get_hazardous_pointer ((gpointer volatile*)&domain->jit_info_table, hp, JIT_INFO_TABLE_HAZARD_INDEX);
395 chunk_pos = jit_info_table_index (table, (gint8*)addr);
396 g_assert (chunk_pos < table->num_chunks);
398 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], hp, (gint8*)addr);
400 /* We now have a position that's very close to that of the
401 first element whose end address is higher than the one
402 we're looking for. If we don't have the exact position,
403 then we have a position below that one, so we'll just
404 search upward until we find our element. */
405 do {
406 MonoJitInfoTableChunk *chunk = table->chunks [chunk_pos];
408 while (pos < chunk->num_elements) {
409 ji = get_hazardous_pointer ((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
411 ++pos;
413 if (IS_JIT_INFO_TOMBSTONE (ji)) {
414 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
415 continue;
417 if ((gint8*)addr >= (gint8*)ji->code_start
418 && (gint8*)addr < (gint8*)ji->code_start + ji->code_size) {
419 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
420 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
421 return ji;
424 /* If we find a non-tombstone element which is already
425 beyond what we're looking for, we have to end the
426 search. */
427 if ((gint8*)addr < (gint8*)ji->code_start)
428 goto not_found;
431 ++chunk_pos;
432 pos = 0;
433 } while (chunk_pos < table->num_chunks);
435 not_found:
436 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
437 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
439 ji = NULL;
441 /* Maybe its an AOT module */
442 image = mono_jit_info_find_aot_module ((guint8*)addr);
443 if (image)
444 ji = jit_info_find_in_aot_func (domain, image, addr);
446 return ji;
449 static G_GNUC_UNUSED void
450 jit_info_table_check (MonoJitInfoTable *table)
452 int i;
454 for (i = 0; i < table->num_chunks; ++i) {
455 MonoJitInfoTableChunk *chunk = table->chunks [i];
456 int j;
458 g_assert (chunk->refcount > 0 /* && chunk->refcount <= 8 */);
459 if (chunk->refcount > 10)
460 printf("warning: chunk refcount is %d\n", chunk->refcount);
461 g_assert (chunk->num_elements <= MONO_JIT_INFO_TABLE_CHUNK_SIZE);
463 for (j = 0; j < chunk->num_elements; ++j) {
464 MonoJitInfo *this = chunk->data [j];
465 MonoJitInfo *next;
467 g_assert ((gint8*)this->code_start + this->code_size <= chunk->last_code_end);
469 if (j < chunk->num_elements - 1)
470 next = chunk->data [j + 1];
471 else if (i < table->num_chunks - 1) {
472 int k;
474 for (k = i + 1; k < table->num_chunks; ++k)
475 if (table->chunks [k]->num_elements > 0)
476 break;
478 if (k >= table->num_chunks)
479 return;
481 g_assert (table->chunks [k]->num_elements > 0);
482 next = table->chunks [k]->data [0];
483 } else
484 return;
486 g_assert ((gint8*)this->code_start + this->code_size <= (gint8*)next->code_start + next->code_size);
491 static MonoJitInfoTable*
492 jit_info_table_realloc (MonoJitInfoTable *old)
494 int i;
495 int num_elements = jit_info_table_num_elements (old);
496 int required_size;
497 int num_chunks;
498 int new_chunk, new_element;
499 MonoJitInfoTable *new;
501 /* number of needed places for elements needed */
502 required_size = (int)((long)num_elements * JIT_INFO_TABLE_FILL_RATIO_DENOM / JIT_INFO_TABLE_FILL_RATIO_NOM);
503 num_chunks = (required_size + MONO_JIT_INFO_TABLE_CHUNK_SIZE - 1) / MONO_JIT_INFO_TABLE_CHUNK_SIZE;
505 new = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*) * num_chunks);
506 new->domain = old->domain;
507 new->num_chunks = num_chunks;
509 for (i = 0; i < num_chunks; ++i)
510 new->chunks [i] = jit_info_table_new_chunk ();
512 new_chunk = 0;
513 new_element = 0;
514 for (i = 0; i < old->num_chunks; ++i) {
515 MonoJitInfoTableChunk *chunk = old->chunks [i];
516 int chunk_num_elements = chunk->num_elements;
517 int j;
519 for (j = 0; j < chunk_num_elements; ++j) {
520 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j])) {
521 g_assert (new_chunk < num_chunks);
522 new->chunks [new_chunk]->data [new_element] = chunk->data [j];
523 if (++new_element >= JIT_INFO_TABLE_FILLED_NUM_ELEMENTS) {
524 new->chunks [new_chunk]->num_elements = new_element;
525 ++new_chunk;
526 new_element = 0;
532 if (new_chunk < num_chunks) {
533 g_assert (new_chunk == num_chunks - 1);
534 new->chunks [new_chunk]->num_elements = new_element;
535 g_assert (new->chunks [new_chunk]->num_elements > 0);
538 for (i = 0; i < num_chunks; ++i) {
539 MonoJitInfoTableChunk *chunk = new->chunks [i];
540 MonoJitInfo *ji = chunk->data [chunk->num_elements - 1];
542 new->chunks [i]->last_code_end = (gint8*)ji->code_start + ji->code_size;
545 return new;
548 static void
549 jit_info_table_split_chunk (MonoJitInfoTableChunk *chunk, MonoJitInfoTableChunk **new1p, MonoJitInfoTableChunk **new2p)
551 MonoJitInfoTableChunk *new1 = jit_info_table_new_chunk ();
552 MonoJitInfoTableChunk *new2 = jit_info_table_new_chunk ();
554 g_assert (chunk->num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE);
556 new1->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE / 2;
557 new2->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE - new1->num_elements;
559 memcpy ((void*)new1->data, (void*)chunk->data, sizeof (MonoJitInfo*) * new1->num_elements);
560 memcpy ((void*)new2->data, (void*)(chunk->data + new1->num_elements), sizeof (MonoJitInfo*) * new2->num_elements);
562 new1->last_code_end = (gint8*)new1->data [new1->num_elements - 1]->code_start
563 + new1->data [new1->num_elements - 1]->code_size;
564 new2->last_code_end = (gint8*)new2->data [new2->num_elements - 1]->code_start
565 + new2->data [new2->num_elements - 1]->code_size;
567 *new1p = new1;
568 *new2p = new2;
571 static MonoJitInfoTable*
572 jit_info_table_copy_and_split_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
574 MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
575 + sizeof (MonoJitInfoTableChunk*) * (table->num_chunks + 1));
576 int i, j;
578 new_table->domain = table->domain;
579 new_table->num_chunks = table->num_chunks + 1;
581 j = 0;
582 for (i = 0; i < table->num_chunks; ++i) {
583 if (table->chunks [i] == chunk) {
584 jit_info_table_split_chunk (chunk, &new_table->chunks [j], &new_table->chunks [j + 1]);
585 j += 2;
586 } else {
587 new_table->chunks [j] = table->chunks [i];
588 ++new_table->chunks [j]->refcount;
589 ++j;
593 g_assert (j == new_table->num_chunks);
595 return new_table;
598 static MonoJitInfoTableChunk*
599 jit_info_table_purify_chunk (MonoJitInfoTableChunk *old)
601 MonoJitInfoTableChunk *new = jit_info_table_new_chunk ();
602 int i, j;
604 j = 0;
605 for (i = 0; i < old->num_elements; ++i) {
606 if (!IS_JIT_INFO_TOMBSTONE (old->data [i]))
607 new->data [j++] = old->data [i];
610 new->num_elements = j;
611 if (new->num_elements > 0)
612 new->last_code_end = (gint8*)new->data [j - 1]->code_start + new->data [j - 1]->code_size;
613 else
614 new->last_code_end = old->last_code_end;
616 return new;
619 static MonoJitInfoTable*
620 jit_info_table_copy_and_purify_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
622 MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
623 + sizeof (MonoJitInfoTableChunk*) * table->num_chunks);
624 int i, j;
626 new_table->domain = table->domain;
627 new_table->num_chunks = table->num_chunks;
629 j = 0;
630 for (i = 0; i < table->num_chunks; ++i) {
631 if (table->chunks [i] == chunk)
632 new_table->chunks [j++] = jit_info_table_purify_chunk (table->chunks [i]);
633 else {
634 new_table->chunks [j] = table->chunks [i];
635 ++new_table->chunks [j]->refcount;
636 ++j;
640 g_assert (j == new_table->num_chunks);
642 return new_table;
645 /* As we add an element to the table the case can arise that the chunk
646 * to which we need to add is already full. In that case we have to
647 * allocate a new table and do something about that chunk. We have
648 * several strategies:
650 * If the number of elements in the table is below the low watermark
651 * or above the high watermark, we reallocate the whole table.
652 * Otherwise we only concern ourselves with the overflowing chunk:
654 * If there are no tombstones in the chunk then we split the chunk in
655 * two, each half full.
657 * If the chunk does contain tombstones, we just make a new copy of
658 * the chunk without the tombstones, which will have room for at least
659 * the one element we have to add.
661 static MonoJitInfoTable*
662 jit_info_table_chunk_overflow (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
664 int num_elements = jit_info_table_num_elements (table);
665 int i;
667 if (num_elements < JIT_INFO_TABLE_LOW_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)
668 || num_elements > JIT_INFO_TABLE_HIGH_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)) {
669 //printf ("reallocing table\n");
670 return jit_info_table_realloc (table);
673 /* count the number of non-tombstone elements in the chunk */
674 num_elements = 0;
675 for (i = 0; i < chunk->num_elements; ++i) {
676 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [i]))
677 ++num_elements;
680 if (num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
681 //printf ("splitting chunk\n");
682 return jit_info_table_copy_and_split_chunk (table, chunk);
685 //printf ("purifying chunk\n");
686 return jit_info_table_copy_and_purify_chunk (table, chunk);
689 /* We add elements to the table by first making space for them by
690 * shifting the elements at the back to the right, one at a time.
691 * This results in duplicate entries during the process, but during
692 * all the time the table is in a sorted state. Also, when an element
693 * is replaced by another one, the element that replaces it has an end
694 * address that is equal to or lower than that of the replaced
695 * element. That property is necessary to guarantee that when
696 * searching for an element we end up at a position not higher than
697 * the one we're looking for (i.e. we either find the element directly
698 * or we end up to the left of it).
700 void
701 mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
703 MonoJitInfoTable *table;
704 int chunk_pos, pos;
705 MonoJitInfoTableChunk *chunk;
706 int num_elements;
707 int i;
709 g_assert (ji->method != NULL);
711 mono_domain_lock (domain);
713 ++mono_stats.jit_info_table_insert_count;
715 table = domain->jit_info_table;
717 restart:
718 chunk_pos = jit_info_table_index (table, (gint8*)ji->code_start + ji->code_size);
719 g_assert (chunk_pos < table->num_chunks);
720 chunk = table->chunks [chunk_pos];
722 if (chunk->num_elements >= MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
723 MonoJitInfoTable *new_table = jit_info_table_chunk_overflow (table, chunk);
725 /* Debugging code, should be removed. */
726 //jit_info_table_check (new_table);
728 domain->jit_info_table = new_table;
729 mono_memory_barrier ();
730 domain->num_jit_info_tables++;
731 mono_thread_hazardous_free_or_queue (table, (MonoHazardousFreeFunc)jit_info_table_free);
732 table = new_table;
734 goto restart;
737 /* Debugging code, should be removed. */
738 //jit_info_table_check (table);
740 num_elements = chunk->num_elements;
742 pos = jit_info_table_chunk_index (chunk, NULL, (gint8*)ji->code_start + ji->code_size);
744 /* First we need to size up the chunk by one, by copying the
745 last item, or inserting the first one, if the table is
746 empty. */
747 if (num_elements > 0)
748 chunk->data [num_elements] = chunk->data [num_elements - 1];
749 else
750 chunk->data [0] = ji;
751 mono_memory_write_barrier ();
752 chunk->num_elements = ++num_elements;
754 /* Shift the elements up one by one. */
755 for (i = num_elements - 2; i >= pos; --i) {
756 mono_memory_write_barrier ();
757 chunk->data [i + 1] = chunk->data [i];
760 /* Now we have room and can insert the new item. */
761 mono_memory_write_barrier ();
762 chunk->data [pos] = ji;
764 /* Set the high code end address chunk entry. */
765 chunk->last_code_end = (gint8*)chunk->data [chunk->num_elements - 1]->code_start
766 + chunk->data [chunk->num_elements - 1]->code_size;
768 /* Debugging code, should be removed. */
769 //jit_info_table_check (table);
771 mono_domain_unlock (domain);
774 static MonoJitInfo*
775 mono_jit_info_make_tombstone (MonoJitInfo *ji)
777 MonoJitInfo *tombstone = g_new0 (MonoJitInfo, 1);
779 tombstone->code_start = ji->code_start;
780 tombstone->code_size = ji->code_size;
781 tombstone->method = JIT_INFO_TOMBSTONE_MARKER;
783 return tombstone;
787 * LOCKING: domain lock
789 static void
790 mono_jit_info_free_or_queue (MonoDomain *domain, MonoJitInfo *ji)
792 if (domain->num_jit_info_tables <= 1) {
793 /* Can it actually happen that we only have one table
794 but ji is still hazardous? */
795 mono_thread_hazardous_free_or_queue (ji, g_free);
796 } else {
797 domain->jit_info_free_queue = g_slist_prepend (domain->jit_info_free_queue, ji);
801 void
802 mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
804 MonoJitInfoTable *table;
805 MonoJitInfoTableChunk *chunk;
806 gpointer start = ji->code_start;
807 int chunk_pos, pos;
809 mono_domain_lock (domain);
810 table = domain->jit_info_table;
812 ++mono_stats.jit_info_table_remove_count;
814 chunk_pos = jit_info_table_index (table, start);
815 g_assert (chunk_pos < table->num_chunks);
817 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], NULL, start);
819 do {
820 chunk = table->chunks [chunk_pos];
822 while (pos < chunk->num_elements) {
823 if (chunk->data [pos] == ji)
824 goto found;
826 g_assert (IS_JIT_INFO_TOMBSTONE (chunk->data [pos]));
827 g_assert ((guint8*)chunk->data [pos]->code_start + chunk->data [pos]->code_size
828 <= (guint8*)ji->code_start + ji->code_size);
830 ++pos;
833 ++chunk_pos;
834 pos = 0;
835 } while (chunk_pos < table->num_chunks);
837 found:
838 g_assert (chunk->data [pos] == ji);
840 chunk->data [pos] = mono_jit_info_make_tombstone (ji);
842 /* Debugging code, should be removed. */
843 //jit_info_table_check (table);
845 mono_jit_info_free_or_queue (domain, ji);
847 mono_domain_unlock (domain);
850 static MonoAotModuleInfoTable*
851 mono_aot_module_info_table_new (void)
853 return g_array_new (FALSE, FALSE, sizeof (gpointer));
856 static int
857 aot_info_table_index (MonoAotModuleInfoTable *table, char *addr)
859 int left = 0, right = table->len;
861 while (left < right) {
862 int pos = (left + right) / 2;
863 AotModuleInfo *ainfo = g_array_index (table, gpointer, pos);
864 char *start = ainfo->start;
865 char *end = ainfo->end;
867 if (addr < start)
868 right = pos;
869 else if (addr >= end)
870 left = pos + 1;
871 else
872 return pos;
875 return left;
878 void
879 mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
881 AotModuleInfo *ainfo = g_new0 (AotModuleInfo, 1);
882 int pos;
884 ainfo->image = image;
885 ainfo->start = start;
886 ainfo->end = end;
888 mono_appdomains_lock ();
890 if (!aot_modules)
891 aot_modules = mono_aot_module_info_table_new ();
893 pos = aot_info_table_index (aot_modules, start);
895 g_array_insert_val (aot_modules, pos, ainfo);
897 mono_appdomains_unlock ();
900 static MonoImage*
901 mono_jit_info_find_aot_module (guint8* addr)
903 guint left = 0, right;
905 if (!aot_modules)
906 return NULL;
908 mono_appdomains_lock ();
910 right = aot_modules->len;
911 while (left < right) {
912 guint pos = (left + right) / 2;
913 AotModuleInfo *ai = g_array_index (aot_modules, gpointer, pos);
915 if (addr < (guint8*)ai->start)
916 right = pos;
917 else if (addr >= (guint8*)ai->end)
918 left = pos + 1;
919 else {
920 mono_appdomains_unlock ();
921 return ai->image;
925 mono_appdomains_unlock ();
927 return NULL;
930 void
931 mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func)
933 jit_info_find_in_aot_func = func;
936 gpointer
937 mono_jit_info_get_code_start (MonoJitInfo* ji)
939 return ji->code_start;
943 mono_jit_info_get_code_size (MonoJitInfo* ji)
945 return ji->code_size;
948 MonoMethod*
949 mono_jit_info_get_method (MonoJitInfo* ji)
951 return ji->method;
954 static gpointer
955 jit_info_key_extract (gpointer value)
957 MonoJitInfo *info = (MonoJitInfo*)value;
959 return info->method;
962 static gpointer*
963 jit_info_next_value (gpointer value)
965 MonoJitInfo *info = (MonoJitInfo*)value;
967 return (gpointer*)&info->next_jit_code_hash;
970 void
971 mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
973 mono_internal_hash_table_init (jit_code_hash,
974 mono_aligned_addr_hash,
975 jit_info_key_extract,
976 jit_info_next_value);
979 MonoGenericJitInfo*
980 mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
982 if (ji->has_generic_jit_info)
983 return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
984 else
985 return NULL;
989 * mono_jit_info_get_generic_sharing_context:
990 * @ji: a jit info
992 * Returns the jit info's generic sharing context, or NULL if it
993 * doesn't have one.
995 MonoGenericSharingContext*
996 mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
998 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
1000 if (gi)
1001 return gi->generic_sharing_context;
1002 else
1003 return NULL;
1007 * mono_jit_info_set_generic_sharing_context:
1008 * @ji: a jit info
1009 * @gsctx: a generic sharing context
1011 * Sets the jit info's generic sharing context. The jit info must
1012 * have memory allocated for the context.
1014 void
1015 mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
1017 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
1019 g_assert (gi);
1021 gi->generic_sharing_context = gsctx;
1024 MonoTryBlockHoleTableJitInfo*
1025 mono_jit_info_get_try_block_hole_table_info (MonoJitInfo *ji)
1027 if (ji->has_try_block_holes) {
1028 char *ptr = (char*)&ji->clauses [ji->num_clauses];
1029 if (ji->has_generic_jit_info)
1030 ptr += sizeof (MonoGenericJitInfo);
1031 return (MonoTryBlockHoleTableJitInfo*)ptr;
1032 } else {
1033 return NULL;
1036 void
1037 mono_install_create_domain_hook (MonoCreateDomainFunc func)
1039 create_domain_hook = func;
1042 void
1043 mono_install_free_domain_hook (MonoFreeDomainFunc func)
1045 free_domain_hook = func;
1049 * mono_string_equal:
1050 * @s1: First string to compare
1051 * @s2: Second string to compare
1053 * Returns FALSE if the strings differ.
1055 gboolean
1056 mono_string_equal (MonoString *s1, MonoString *s2)
1058 int l1 = mono_string_length (s1);
1059 int l2 = mono_string_length (s2);
1061 if (s1 == s2)
1062 return TRUE;
1063 if (l1 != l2)
1064 return FALSE;
1066 return memcmp (mono_string_chars (s1), mono_string_chars (s2), l1 * 2) == 0;
1070 * mono_string_hash:
1071 * @s: the string to hash
1073 * Returns the hash for the string.
1075 guint
1076 mono_string_hash (MonoString *s)
1078 const guint16 *p = mono_string_chars (s);
1079 int i, len = mono_string_length (s);
1080 guint h = 0;
1082 for (i = 0; i < len; i++) {
1083 h = (h << 5) - h + *p;
1084 p++;
1087 return h;
1090 static gboolean
1091 mono_ptrarray_equal (gpointer *s1, gpointer *s2)
1093 int len = GPOINTER_TO_INT (s1 [0]);
1094 if (len != GPOINTER_TO_INT (s2 [0]))
1095 return FALSE;
1097 return memcmp (s1 + 1, s2 + 1, len * sizeof(gpointer)) == 0;
1100 static guint
1101 mono_ptrarray_hash (gpointer *s)
1103 int i;
1104 int len = GPOINTER_TO_INT (s [0]);
1105 guint hash = 0;
1107 for (i = 1; i < len; i++)
1108 hash += GPOINTER_TO_UINT (s [i]);
1110 return hash;
1114 * Allocate an id for domain and set domain->domain_id.
1115 * LOCKING: must be called while holding appdomains_mutex.
1116 * We try to assign low numbers to the domain, so it can be used
1117 * as an index in data tables to lookup domain-specific info
1118 * with minimal memory overhead. We also try not to reuse the
1119 * same id too quickly (to help debugging).
1121 static int
1122 domain_id_alloc (MonoDomain *domain)
1124 int id = -1, i;
1125 if (!appdomains_list) {
1126 appdomain_list_size = 2;
1127 appdomains_list = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1129 for (i = appdomain_next; i < appdomain_list_size; ++i) {
1130 if (!appdomains_list [i]) {
1131 id = i;
1132 break;
1135 if (id == -1) {
1136 for (i = 0; i < appdomain_next; ++i) {
1137 if (!appdomains_list [i]) {
1138 id = i;
1139 break;
1143 if (id == -1) {
1144 MonoDomain **new_list;
1145 int new_size = appdomain_list_size * 2;
1146 if (new_size >= (1 << 16))
1147 g_assert_not_reached ();
1148 id = appdomain_list_size;
1149 new_list = mono_gc_alloc_fixed (new_size * sizeof (void*), NULL);
1150 memcpy (new_list, appdomains_list, appdomain_list_size * sizeof (void*));
1151 mono_gc_free_fixed (appdomains_list);
1152 appdomains_list = new_list;
1153 appdomain_list_size = new_size;
1155 domain->domain_id = id;
1156 appdomains_list [id] = domain;
1157 appdomain_next++;
1158 if (appdomain_next > appdomain_list_size)
1159 appdomain_next = 0;
1160 return id;
1163 static guint32 domain_gc_bitmap [sizeof(MonoDomain)/4/32 + 1];
1164 static gpointer domain_gc_desc = NULL;
1165 static guint32 domain_shadow_serial = 0L;
1167 MonoDomain *
1168 mono_domain_create (void)
1170 MonoDomain *domain;
1171 guint32 shadow_serial;
1173 mono_appdomains_lock ();
1174 shadow_serial = domain_shadow_serial++;
1176 if (!domain_gc_desc) {
1177 unsigned int i, bit = 0;
1178 for (i = G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_OBJECT); i < G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_GC_TRACKED); i += sizeof (gpointer)) {
1179 bit = i / sizeof (gpointer);
1180 domain_gc_bitmap [bit / 32] |= 1 << (bit % 32);
1182 domain_gc_desc = mono_gc_make_descr_from_bitmap ((gsize*)domain_gc_bitmap, bit + 1);
1184 mono_appdomains_unlock ();
1186 domain = mono_gc_alloc_fixed (sizeof (MonoDomain), domain_gc_desc);
1187 domain->shadow_serial = shadow_serial;
1188 domain->domain = NULL;
1189 domain->setup = NULL;
1190 domain->friendly_name = NULL;
1191 domain->search_path = NULL;
1193 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);
1195 mono_profiler_appdomain_event (domain, MONO_PROFILE_START_LOAD);
1197 domain->mp = mono_mempool_new ();
1198 domain->code_mp = mono_code_manager_new ();
1199 domain->env = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1200 domain->domain_assemblies = NULL;
1201 domain->assembly_bindings = NULL;
1202 domain->assembly_bindings_parsed = FALSE;
1203 domain->class_vtable_array = g_ptr_array_new ();
1204 domain->proxy_vtable_hash = g_hash_table_new ((GHashFunc)mono_ptrarray_hash, (GCompareFunc)mono_ptrarray_equal);
1205 domain->static_data_array = NULL;
1206 mono_jit_code_hash_init (&domain->jit_code_hash);
1207 domain->ldstr_table = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1208 domain->num_jit_info_tables = 1;
1209 domain->jit_info_table = jit_info_table_new (domain);
1210 domain->jit_info_free_queue = NULL;
1211 domain->finalizable_objects_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1212 #ifndef HAVE_SGEN_GC
1213 domain->track_resurrection_handles_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1214 #endif
1216 InitializeCriticalSection (&domain->lock);
1217 InitializeCriticalSection (&domain->assemblies_lock);
1218 InitializeCriticalSection (&domain->jit_code_hash_lock);
1219 InitializeCriticalSection (&domain->finalizable_objects_hash_lock);
1221 domain->method_rgctx_hash = NULL;
1223 mono_appdomains_lock ();
1224 domain_id_alloc (domain);
1225 mono_appdomains_unlock ();
1227 mono_perfcounters->loader_appdomains++;
1228 mono_perfcounters->loader_total_appdomains++;
1230 mono_debug_domain_create (domain);
1232 if (create_domain_hook)
1233 create_domain_hook (domain);
1235 mono_profiler_appdomain_loaded (domain, MONO_PROFILE_OK);
1237 return domain;
1241 * mono_init_internal:
1243 * Creates the initial application domain and initializes the mono_defaults
1244 * structure.
1245 * This function is guaranteed to not run any IL code.
1246 * If exe_filename is not NULL, the method will determine the required runtime
1247 * from the exe configuration file or the version PE field.
1248 * If runtime_version is not NULL, that runtime version will be used.
1249 * Either exe_filename or runtime_version must be provided.
1251 * Returns: the initial domain.
1253 static MonoDomain *
1254 mono_init_internal (const char *filename, const char *exe_filename, const char *runtime_version)
1256 static MonoDomain *domain = NULL;
1257 MonoAssembly *ass = NULL;
1258 MonoImageOpenStatus status = MONO_IMAGE_OK;
1259 const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
1260 int n;
1262 if (domain)
1263 g_assert_not_reached ();
1265 #ifdef HOST_WIN32
1266 /* Avoid system error message boxes. */
1267 SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1269 mono_load_coree (exe_filename);
1270 #endif
1272 mono_perfcounters_init ();
1274 mono_counters_register ("Max native code in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_size);
1275 mono_counters_register ("Max code space allocated in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_alloc);
1276 mono_counters_register ("Total code space allocated", MONO_COUNTER_INT|MONO_COUNTER_JIT, &total_domain_code_alloc);
1278 mono_gc_base_init ();
1280 appdomain_thread_id = TlsAlloc ();
1282 InitializeCriticalSection (&appdomains_mutex);
1284 mono_metadata_init ();
1285 mono_images_init ();
1286 mono_assemblies_init ();
1287 mono_classes_init ();
1288 mono_loader_init ();
1289 mono_reflection_init ();
1291 /* FIXME: When should we release this memory? */
1292 MONO_GC_REGISTER_ROOT (appdomains_list);
1294 domain = mono_domain_create ();
1295 mono_root_domain = domain;
1297 SET_APPDOMAIN (domain);
1299 /* Get a list of runtimes supported by the exe */
1300 if (exe_filename != NULL) {
1302 * This function will load the exe file as a MonoImage. We need to close it, but
1303 * that would mean it would be reloaded later. So instead, we save it to
1304 * exe_image, and close it during shutdown.
1306 get_runtimes_from_exe (exe_filename, &exe_image, runtimes);
1307 #ifdef HOST_WIN32
1308 if (!exe_image) {
1309 exe_image = mono_assembly_open_from_bundle (exe_filename, NULL, FALSE);
1310 if (!exe_image)
1311 exe_image = mono_image_open (exe_filename, NULL);
1313 mono_fixup_exe_image (exe_image);
1314 #endif
1315 } else if (runtime_version != NULL) {
1316 runtimes [0] = get_runtime_by_version (runtime_version);
1317 runtimes [1] = NULL;
1320 if (runtimes [0] == NULL) {
1321 const MonoRuntimeInfo *default_runtime = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
1322 runtimes [0] = default_runtime;
1323 runtimes [1] = NULL;
1324 g_print ("WARNING: The runtime version supported by this application is unavailable.\n");
1325 g_print ("Using default runtime: %s\n", default_runtime->runtime_version);
1328 /* The selected runtime will be the first one for which there is a mscrolib.dll */
1329 for (n = 0; runtimes [n] != NULL && ass == NULL; n++) {
1330 current_runtime = runtimes [n];
1331 ass = mono_assembly_load_corlib (current_runtime, &status);
1332 if (status != MONO_IMAGE_OK && status != MONO_IMAGE_ERROR_ERRNO)
1333 break;
1337 if ((status != MONO_IMAGE_OK) || (ass == NULL)) {
1338 switch (status){
1339 case MONO_IMAGE_ERROR_ERRNO: {
1340 char *corlib_file = g_build_filename (mono_assembly_getrootdir (), "mono", current_runtime->framework_version, "mscorlib.dll", NULL);
1341 g_print ("The assembly mscorlib.dll was not found or could not be loaded.\n");
1342 g_print ("It should have been installed in the `%s' directory.\n", corlib_file);
1343 g_free (corlib_file);
1344 break;
1346 case MONO_IMAGE_IMAGE_INVALID:
1347 g_print ("The file %s/mscorlib.dll is an invalid CIL image\n",
1348 mono_assembly_getrootdir ());
1349 break;
1350 case MONO_IMAGE_MISSING_ASSEMBLYREF:
1351 g_print ("Missing assembly reference in %s/mscorlib.dll\n",
1352 mono_assembly_getrootdir ());
1353 break;
1354 case MONO_IMAGE_OK:
1355 /* to suppress compiler warning */
1356 break;
1359 exit (1);
1361 mono_defaults.corlib = mono_assembly_get_image (ass);
1363 mono_defaults.object_class = mono_class_from_name (
1364 mono_defaults.corlib, "System", "Object");
1365 g_assert (mono_defaults.object_class != 0);
1367 mono_defaults.void_class = mono_class_from_name (
1368 mono_defaults.corlib, "System", "Void");
1369 g_assert (mono_defaults.void_class != 0);
1371 mono_defaults.boolean_class = mono_class_from_name (
1372 mono_defaults.corlib, "System", "Boolean");
1373 g_assert (mono_defaults.boolean_class != 0);
1375 mono_defaults.byte_class = mono_class_from_name (
1376 mono_defaults.corlib, "System", "Byte");
1377 g_assert (mono_defaults.byte_class != 0);
1379 mono_defaults.sbyte_class = mono_class_from_name (
1380 mono_defaults.corlib, "System", "SByte");
1381 g_assert (mono_defaults.sbyte_class != 0);
1383 mono_defaults.int16_class = mono_class_from_name (
1384 mono_defaults.corlib, "System", "Int16");
1385 g_assert (mono_defaults.int16_class != 0);
1387 mono_defaults.uint16_class = mono_class_from_name (
1388 mono_defaults.corlib, "System", "UInt16");
1389 g_assert (mono_defaults.uint16_class != 0);
1391 mono_defaults.int32_class = mono_class_from_name (
1392 mono_defaults.corlib, "System", "Int32");
1393 g_assert (mono_defaults.int32_class != 0);
1395 mono_defaults.uint32_class = mono_class_from_name (
1396 mono_defaults.corlib, "System", "UInt32");
1397 g_assert (mono_defaults.uint32_class != 0);
1399 mono_defaults.uint_class = mono_class_from_name (
1400 mono_defaults.corlib, "System", "UIntPtr");
1401 g_assert (mono_defaults.uint_class != 0);
1403 mono_defaults.int_class = mono_class_from_name (
1404 mono_defaults.corlib, "System", "IntPtr");
1405 g_assert (mono_defaults.int_class != 0);
1407 mono_defaults.int64_class = mono_class_from_name (
1408 mono_defaults.corlib, "System", "Int64");
1409 g_assert (mono_defaults.int64_class != 0);
1411 mono_defaults.uint64_class = mono_class_from_name (
1412 mono_defaults.corlib, "System", "UInt64");
1413 g_assert (mono_defaults.uint64_class != 0);
1415 mono_defaults.single_class = mono_class_from_name (
1416 mono_defaults.corlib, "System", "Single");
1417 g_assert (mono_defaults.single_class != 0);
1419 mono_defaults.double_class = mono_class_from_name (
1420 mono_defaults.corlib, "System", "Double");
1421 g_assert (mono_defaults.double_class != 0);
1423 mono_defaults.char_class = mono_class_from_name (
1424 mono_defaults.corlib, "System", "Char");
1425 g_assert (mono_defaults.char_class != 0);
1427 mono_defaults.string_class = mono_class_from_name (
1428 mono_defaults.corlib, "System", "String");
1429 g_assert (mono_defaults.string_class != 0);
1431 mono_defaults.enum_class = mono_class_from_name (
1432 mono_defaults.corlib, "System", "Enum");
1433 g_assert (mono_defaults.enum_class != 0);
1435 mono_defaults.array_class = mono_class_from_name (
1436 mono_defaults.corlib, "System", "Array");
1437 g_assert (mono_defaults.array_class != 0);
1439 mono_defaults.delegate_class = mono_class_from_name (
1440 mono_defaults.corlib, "System", "Delegate");
1441 g_assert (mono_defaults.delegate_class != 0 );
1443 mono_defaults.multicastdelegate_class = mono_class_from_name (
1444 mono_defaults.corlib, "System", "MulticastDelegate");
1445 g_assert (mono_defaults.multicastdelegate_class != 0 );
1447 mono_defaults.asyncresult_class = mono_class_from_name (
1448 mono_defaults.corlib, "System.Runtime.Remoting.Messaging",
1449 "AsyncResult");
1450 g_assert (mono_defaults.asyncresult_class != 0 );
1452 mono_defaults.manualresetevent_class = mono_class_from_name (
1453 mono_defaults.corlib, "System.Threading", "ManualResetEvent");
1454 g_assert (mono_defaults.manualresetevent_class != 0 );
1456 mono_defaults.typehandle_class = mono_class_from_name (
1457 mono_defaults.corlib, "System", "RuntimeTypeHandle");
1458 g_assert (mono_defaults.typehandle_class != 0);
1460 mono_defaults.methodhandle_class = mono_class_from_name (
1461 mono_defaults.corlib, "System", "RuntimeMethodHandle");
1462 g_assert (mono_defaults.methodhandle_class != 0);
1464 mono_defaults.fieldhandle_class = mono_class_from_name (
1465 mono_defaults.corlib, "System", "RuntimeFieldHandle");
1466 g_assert (mono_defaults.fieldhandle_class != 0);
1468 mono_defaults.systemtype_class = mono_class_from_name (
1469 mono_defaults.corlib, "System", "Type");
1470 g_assert (mono_defaults.systemtype_class != 0);
1472 mono_defaults.monotype_class = mono_class_from_name (
1473 mono_defaults.corlib, "System", "MonoType");
1474 g_assert (mono_defaults.monotype_class != 0);
1476 mono_defaults.exception_class = mono_class_from_name (
1477 mono_defaults.corlib, "System", "Exception");
1478 g_assert (mono_defaults.exception_class != 0);
1480 mono_defaults.threadabortexception_class = mono_class_from_name (
1481 mono_defaults.corlib, "System.Threading", "ThreadAbortException");
1482 g_assert (mono_defaults.threadabortexception_class != 0);
1484 mono_defaults.thread_class = mono_class_from_name (
1485 mono_defaults.corlib, "System.Threading", "Thread");
1486 g_assert (mono_defaults.thread_class != 0);
1488 mono_defaults.internal_thread_class = mono_class_from_name (
1489 mono_defaults.corlib, "System.Threading", "InternalThread");
1490 if (!mono_defaults.internal_thread_class) {
1491 /* This can happen with an old mscorlib */
1492 fprintf (stderr, "Corlib too old for this runtime.\n");
1493 fprintf (stderr, "Loaded from: %s\n",
1494 mono_defaults.corlib? mono_image_get_filename (mono_defaults.corlib): "unknown");
1495 exit (1);
1498 mono_defaults.appdomain_class = mono_class_from_name (
1499 mono_defaults.corlib, "System", "AppDomain");
1500 g_assert (mono_defaults.appdomain_class != 0);
1502 mono_defaults.transparent_proxy_class = mono_class_from_name (
1503 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "TransparentProxy");
1504 g_assert (mono_defaults.transparent_proxy_class != 0);
1506 mono_defaults.real_proxy_class = mono_class_from_name (
1507 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "RealProxy");
1508 g_assert (mono_defaults.real_proxy_class != 0);
1510 mono_defaults.mono_method_message_class = mono_class_from_name (
1511 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", "MonoMethodMessage");
1512 g_assert (mono_defaults.mono_method_message_class != 0);
1514 mono_defaults.field_info_class = mono_class_from_name (
1515 mono_defaults.corlib, "System.Reflection", "FieldInfo");
1516 g_assert (mono_defaults.field_info_class != 0);
1518 mono_defaults.method_info_class = mono_class_from_name (
1519 mono_defaults.corlib, "System.Reflection", "MethodInfo");
1520 g_assert (mono_defaults.method_info_class != 0);
1522 mono_defaults.stringbuilder_class = mono_class_from_name (
1523 mono_defaults.corlib, "System.Text", "StringBuilder");
1524 g_assert (mono_defaults.stringbuilder_class != 0);
1526 mono_defaults.math_class = mono_class_from_name (
1527 mono_defaults.corlib, "System", "Math");
1528 g_assert (mono_defaults.math_class != 0);
1530 mono_defaults.stack_frame_class = mono_class_from_name (
1531 mono_defaults.corlib, "System.Diagnostics", "StackFrame");
1532 g_assert (mono_defaults.stack_frame_class != 0);
1534 mono_defaults.stack_trace_class = mono_class_from_name (
1535 mono_defaults.corlib, "System.Diagnostics", "StackTrace");
1536 g_assert (mono_defaults.stack_trace_class != 0);
1538 mono_defaults.marshal_class = mono_class_from_name (
1539 mono_defaults.corlib, "System.Runtime.InteropServices", "Marshal");
1540 g_assert (mono_defaults.marshal_class != 0);
1542 mono_defaults.iserializeable_class = mono_class_from_name (
1543 mono_defaults.corlib, "System.Runtime.Serialization", "ISerializable");
1544 g_assert (mono_defaults.iserializeable_class != 0);
1546 mono_defaults.serializationinfo_class = mono_class_from_name (
1547 mono_defaults.corlib, "System.Runtime.Serialization", "SerializationInfo");
1548 g_assert (mono_defaults.serializationinfo_class != 0);
1550 mono_defaults.streamingcontext_class = mono_class_from_name (
1551 mono_defaults.corlib, "System.Runtime.Serialization", "StreamingContext");
1552 g_assert (mono_defaults.streamingcontext_class != 0);
1554 mono_defaults.typed_reference_class = mono_class_from_name (
1555 mono_defaults.corlib, "System", "TypedReference");
1556 g_assert (mono_defaults.typed_reference_class != 0);
1558 mono_defaults.argumenthandle_class = mono_class_from_name (
1559 mono_defaults.corlib, "System", "RuntimeArgumentHandle");
1560 g_assert (mono_defaults.argumenthandle_class != 0);
1562 mono_defaults.marshalbyrefobject_class = mono_class_from_name (
1563 mono_defaults.corlib, "System", "MarshalByRefObject");
1564 g_assert (mono_defaults.marshalbyrefobject_class != 0);
1566 mono_defaults.monitor_class = mono_class_from_name (
1567 mono_defaults.corlib, "System.Threading", "Monitor");
1568 g_assert (mono_defaults.monitor_class != 0);
1570 mono_defaults.iremotingtypeinfo_class = mono_class_from_name (
1571 mono_defaults.corlib, "System.Runtime.Remoting", "IRemotingTypeInfo");
1572 g_assert (mono_defaults.iremotingtypeinfo_class != 0);
1574 mono_defaults.runtimesecurityframe_class = mono_class_from_name (
1575 mono_defaults.corlib, "System.Security", "RuntimeSecurityFrame");
1577 mono_defaults.executioncontext_class = mono_class_from_name (
1578 mono_defaults.corlib, "System.Threading", "ExecutionContext");
1580 mono_defaults.internals_visible_class = mono_class_from_name (
1581 mono_defaults.corlib, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute");
1583 mono_defaults.critical_finalizer_object = mono_class_from_name (
1584 mono_defaults.corlib, "System.Runtime.ConstrainedExecution", "CriticalFinalizerObject");
1587 * mscorlib needs a little help, only now it can load its friends list (after we have
1588 * loaded the InternalsVisibleToAttribute), load it now
1590 mono_assembly_load_friends (ass);
1592 mono_defaults.safehandle_class = mono_class_from_name (
1593 mono_defaults.corlib, "System.Runtime.InteropServices", "SafeHandle");
1595 mono_defaults.handleref_class = mono_class_from_name (
1596 mono_defaults.corlib, "System.Runtime.InteropServices", "HandleRef");
1598 mono_defaults.attribute_class = mono_class_from_name (
1599 mono_defaults.corlib, "System", "Attribute");
1601 mono_defaults.customattribute_data_class = mono_class_from_name (
1602 mono_defaults.corlib, "System.Reflection", "CustomAttributeData");
1604 /* these are initialized lazily when COM features are used */
1605 mono_defaults.variant_class = NULL;
1606 mono_defaults.com_object_class = NULL;
1607 mono_defaults.com_interop_proxy_class = NULL;
1608 mono_defaults.iunknown_class = NULL;
1609 mono_defaults.idispatch_class = NULL;
1612 * Note that mono_defaults.generic_*_class is only non-NULL if we're
1613 * using the 2.0 corlib.
1615 mono_class_init (mono_defaults.array_class);
1616 mono_defaults.generic_nullable_class = mono_class_from_name (
1617 mono_defaults.corlib, "System", "Nullable`1");
1618 mono_defaults.generic_ilist_class = mono_class_from_name (
1619 mono_defaults.corlib, "System.Collections.Generic", "IList`1");
1621 domain->friendly_name = g_path_get_basename (filename);
1623 _mono_debug_init_corlib (domain);
1625 return domain;
1629 * mono_init:
1631 * Creates the initial application domain and initializes the mono_defaults
1632 * structure.
1633 * This function is guaranteed to not run any IL code.
1634 * The runtime is initialized using the default runtime version.
1636 * Returns: the initial domain.
1638 MonoDomain *
1639 mono_init (const char *domain_name)
1641 return mono_init_internal (domain_name, NULL, DEFAULT_RUNTIME_VERSION);
1645 * mono_init_from_assembly:
1647 * Creates the initial application domain and initializes the mono_defaults
1648 * structure.
1649 * This function is guaranteed to not run any IL code.
1650 * The runtime is initialized using the runtime version required by the
1651 * provided executable. The version is determined by looking at the exe
1652 * configuration file and the version PE field)
1654 * Returns: the initial domain.
1656 MonoDomain *
1657 mono_init_from_assembly (const char *domain_name, const char *filename)
1659 return mono_init_internal (domain_name, filename, NULL);
1663 * mono_init_version:
1665 * Creates the initial application domain and initializes the mono_defaults
1666 * structure.
1667 * This function is guaranteed to not run any IL code.
1668 * The runtime is initialized using the provided rutime version.
1670 * Returns: the initial domain.
1672 MonoDomain *
1673 mono_init_version (const char *domain_name, const char *version)
1675 return mono_init_internal (domain_name, NULL, version);
1679 * mono_init_com_types:
1681 * Initializes all types needed for COM Interop in mono_defaults structure.
1683 void
1684 mono_init_com_types (void)
1686 static gboolean initialized = FALSE;
1688 if (initialized)
1689 return;
1691 /* FIXME: do I need some threading protection here */
1693 g_assert (mono_defaults.corlib);
1695 mono_defaults.variant_class = mono_class_from_name (
1696 mono_defaults.corlib, "System", "Variant");
1697 g_assert (mono_defaults.variant_class != 0);
1699 mono_defaults.com_object_class = mono_class_from_name (
1700 mono_defaults.corlib, "System", "__ComObject");
1701 g_assert (mono_defaults.com_object_class != 0);
1703 mono_defaults.com_interop_proxy_class = mono_class_from_name (
1704 mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
1705 g_assert (mono_defaults.com_interop_proxy_class != 0);
1707 mono_defaults.iunknown_class = mono_class_from_name (
1708 mono_defaults.corlib, "Mono.Interop", "IUnknown");
1709 g_assert (mono_defaults.iunknown_class != 0);
1711 mono_defaults.idispatch_class = mono_class_from_name (
1712 mono_defaults.corlib, "Mono.Interop", "IDispatch");
1713 g_assert (mono_defaults.idispatch_class != 0);
1715 initialized = TRUE;
1719 * mono_cleanup:
1721 * Cleans up all metadata modules.
1723 void
1724 mono_cleanup (void)
1726 mono_close_exe_image ();
1728 mono_loader_cleanup ();
1729 mono_classes_cleanup ();
1730 mono_assemblies_cleanup ();
1731 mono_images_cleanup ();
1732 mono_debug_cleanup ();
1733 mono_metadata_cleanup ();
1735 TlsFree (appdomain_thread_id);
1736 DeleteCriticalSection (&appdomains_mutex);
1739 void
1740 mono_close_exe_image (void)
1742 if (exe_image)
1743 mono_image_close (exe_image);
1747 * mono_get_root_domain:
1749 * The root AppDomain is the initial domain created by the runtime when it is
1750 * initialized. Programs execute on this AppDomain, but can create new ones
1751 * later. Currently there is no unmanaged API to create new AppDomains, this
1752 * must be done from managed code.
1754 * Returns: the root appdomain, to obtain the current domain, use mono_domain_get ()
1756 MonoDomain*
1757 mono_get_root_domain (void)
1759 return mono_root_domain;
1763 * mono_domain_get:
1765 * Returns: the current domain, to obtain the root domain use
1766 * mono_get_root_domain().
1768 MonoDomain *
1769 mono_domain_get ()
1771 return GET_APPDOMAIN ();
1774 void
1775 mono_domain_unset (void)
1777 SET_APPDOMAIN (NULL);
1780 void
1781 mono_domain_set_internal_with_options (MonoDomain *domain, gboolean migrate_exception)
1783 MonoInternalThread *thread;
1785 if (mono_domain_get () == domain)
1786 return;
1788 SET_APPDOMAIN (domain);
1789 SET_APPCONTEXT (domain->default_context);
1791 if (migrate_exception) {
1792 thread = mono_thread_internal_current ();
1793 if (!thread->abort_exc)
1794 return;
1796 g_assert (thread->abort_exc->object.vtable->domain != domain);
1797 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
1798 g_assert (thread->abort_exc->object.vtable->domain == domain);
1803 * mono_domain_set_internal:
1804 * @domain: the new domain
1806 * Sets the current domain to @domain.
1808 void
1809 mono_domain_set_internal (MonoDomain *domain)
1811 mono_domain_set_internal_with_options (domain, TRUE);
1814 void
1815 mono_domain_foreach (MonoDomainFunc func, gpointer user_data)
1817 int i, size;
1818 MonoDomain **copy;
1821 * Create a copy of the data to avoid calling the user callback
1822 * inside the lock because that could lead to deadlocks.
1823 * We can do this because this function is not perf. critical.
1825 mono_appdomains_lock ();
1826 size = appdomain_list_size;
1827 copy = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1828 memcpy (copy, appdomains_list, appdomain_list_size * sizeof (void*));
1829 mono_appdomains_unlock ();
1831 for (i = 0; i < size; ++i) {
1832 if (copy [i])
1833 func (copy [i], user_data);
1836 mono_gc_free_fixed (copy);
1840 * mono_domain_assembly_open:
1841 * @domain: the application domain
1842 * @name: file name of the assembly
1844 * fixme: maybe we should integrate this with mono_assembly_open ??
1846 MonoAssembly *
1847 mono_domain_assembly_open (MonoDomain *domain, const char *name)
1849 MonoDomain *current;
1850 MonoAssembly *ass;
1851 GSList *tmp;
1853 mono_domain_assemblies_lock (domain);
1854 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1855 ass = tmp->data;
1856 if (strcmp (name, ass->aname.name) == 0) {
1857 mono_domain_assemblies_unlock (domain);
1858 return ass;
1861 mono_domain_assemblies_unlock (domain);
1863 if (domain != mono_domain_get ()) {
1864 current = mono_domain_get ();
1866 mono_domain_set (domain, FALSE);
1867 ass = mono_assembly_open (name, NULL);
1868 mono_domain_set (current, FALSE);
1869 } else {
1870 ass = mono_assembly_open (name, NULL);
1873 return ass;
1876 #ifndef HAVE_SGEN_GC
1877 static void
1878 free_slist (gpointer key, gpointer value, gpointer user_data)
1880 g_slist_free (value);
1882 #endif
1884 #if HAVE_SGEN_GC
1885 static void
1886 unregister_vtable_reflection_type (MonoVTable *vtable)
1888 MonoObject *type = vtable->type;
1890 if (type->vtable->klass != mono_defaults.monotype_class)
1891 mono_gc_deregister_root ((char*)&vtable->type);
1893 #endif
1895 void
1896 mono_domain_free (MonoDomain *domain, gboolean force)
1898 int code_size, code_alloc;
1899 GSList *tmp;
1900 if ((domain == mono_root_domain) && !force) {
1901 g_warning ("cant unload root domain");
1902 return;
1905 if (mono_dont_free_domains)
1906 return;
1908 mono_profiler_appdomain_event (domain, MONO_PROFILE_START_UNLOAD);
1910 mono_debug_domain_unload (domain);
1912 mono_appdomains_lock ();
1913 appdomains_list [domain->domain_id] = NULL;
1914 mono_appdomains_unlock ();
1916 /* must do this early as it accesses fields and types */
1917 if (domain->special_static_fields) {
1918 mono_alloc_special_static_data_free (domain->special_static_fields);
1919 g_hash_table_destroy (domain->special_static_fields);
1920 domain->special_static_fields = NULL;
1924 * We must destroy all these hash tables here because they
1925 * contain references to managed objects belonging to the
1926 * domain. Once we let the GC clear the domain there must be
1927 * no more such references, or we'll crash if a collection
1928 * occurs.
1930 mono_g_hash_table_destroy (domain->ldstr_table);
1931 domain->ldstr_table = NULL;
1933 mono_g_hash_table_destroy (domain->env);
1934 domain->env = NULL;
1936 mono_reflection_cleanup_domain (domain);
1938 if (domain->type_hash) {
1939 mono_g_hash_table_destroy (domain->type_hash);
1940 domain->type_hash = NULL;
1942 if (domain->type_init_exception_hash) {
1943 mono_g_hash_table_destroy (domain->type_init_exception_hash);
1944 domain->type_init_exception_hash = NULL;
1947 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1948 MonoAssembly *ass = tmp->data;
1949 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading domain %s %p, assembly %s %p, refcount=%d\n", domain->friendly_name, domain, ass->aname.name, ass, ass->ref_count);
1950 if (!mono_assembly_close_except_image_pools (ass))
1951 tmp->data = NULL;
1954 #if HAVE_SGEN_GC
1955 if (domain->class_vtable_array) {
1956 int i;
1957 for (i = 0; i < domain->class_vtable_array->len; ++i)
1958 unregister_vtable_reflection_type (g_ptr_array_index (domain->class_vtable_array, i));
1960 #endif
1962 mono_gc_clear_domain (domain);
1964 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1965 MonoAssembly *ass = tmp->data;
1966 if (ass)
1967 mono_assembly_close_finish (ass);
1969 g_slist_free (domain->domain_assemblies);
1970 domain->domain_assemblies = NULL;
1973 * Send this after the assemblies have been unloaded and the domain is still in a
1974 * usable state.
1976 mono_profiler_appdomain_event (domain, MONO_PROFILE_END_UNLOAD);
1978 if (free_domain_hook)
1979 free_domain_hook (domain);
1981 /* FIXME: free delegate_hash_table when it's used */
1982 if (domain->search_path) {
1983 g_strfreev (domain->search_path);
1984 domain->search_path = NULL;
1986 domain->create_proxy_for_type_method = NULL;
1987 domain->private_invoke_method = NULL;
1988 domain->default_context = NULL;
1989 domain->out_of_memory_ex = NULL;
1990 domain->null_reference_ex = NULL;
1991 domain->stack_overflow_ex = NULL;
1992 domain->entry_assembly = NULL;
1994 g_free (domain->friendly_name);
1995 domain->friendly_name = NULL;
1996 g_ptr_array_free (domain->class_vtable_array, TRUE);
1997 domain->class_vtable_array = NULL;
1998 g_hash_table_destroy (domain->proxy_vtable_hash);
1999 domain->proxy_vtable_hash = NULL;
2000 if (domain->static_data_array) {
2001 mono_gc_free_fixed (domain->static_data_array);
2002 domain->static_data_array = NULL;
2004 mono_internal_hash_table_destroy (&domain->jit_code_hash);
2007 * There might still be jit info tables of this domain which
2008 * are not freed. Since the domain cannot be in use anymore,
2009 * this will free them.
2011 mono_thread_hazardous_try_free_all ();
2012 g_assert (domain->num_jit_info_tables == 1);
2013 jit_info_table_free (domain->jit_info_table);
2014 domain->jit_info_table = NULL;
2015 g_assert (!domain->jit_info_free_queue);
2017 /* collect statistics */
2018 code_alloc = mono_code_manager_size (domain->code_mp, &code_size);
2019 total_domain_code_alloc += code_alloc;
2020 max_domain_code_alloc = MAX (max_domain_code_alloc, code_alloc);
2021 max_domain_code_size = MAX (max_domain_code_size, code_size);
2023 #ifdef DEBUG_DOMAIN_UNLOAD
2024 mono_mempool_invalidate (domain->mp);
2025 mono_code_manager_invalidate (domain->code_mp);
2026 #else
2027 mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (domain->mp);
2028 mono_mempool_destroy (domain->mp);
2029 domain->mp = NULL;
2030 mono_code_manager_destroy (domain->code_mp);
2031 domain->code_mp = NULL;
2032 #endif
2034 g_hash_table_destroy (domain->finalizable_objects_hash);
2035 domain->finalizable_objects_hash = NULL;
2036 #ifndef HAVE_SGEN_GC
2037 if (domain->track_resurrection_objects_hash) {
2038 g_hash_table_foreach (domain->track_resurrection_objects_hash, free_slist, NULL);
2039 g_hash_table_destroy (domain->track_resurrection_objects_hash);
2041 if (domain->track_resurrection_handles_hash)
2042 g_hash_table_destroy (domain->track_resurrection_handles_hash);
2043 #endif
2044 if (domain->method_rgctx_hash) {
2045 g_hash_table_destroy (domain->method_rgctx_hash);
2046 domain->method_rgctx_hash = NULL;
2048 if (domain->generic_virtual_cases) {
2049 g_hash_table_destroy (domain->generic_virtual_cases);
2050 domain->generic_virtual_cases = NULL;
2053 DeleteCriticalSection (&domain->finalizable_objects_hash_lock);
2054 DeleteCriticalSection (&domain->assemblies_lock);
2055 DeleteCriticalSection (&domain->jit_code_hash_lock);
2056 DeleteCriticalSection (&domain->lock);
2057 domain->setup = NULL;
2059 mono_gc_deregister_root ((char*)&(domain->MONO_DOMAIN_FIRST_GC_TRACKED));
2061 /* FIXME: anything else required ? */
2063 mono_gc_free_fixed (domain);
2065 mono_perfcounters->loader_appdomains--;
2067 if ((domain == mono_root_domain))
2068 mono_root_domain = NULL;
2072 * mono_domain_get_id:
2073 * @domainid: the ID
2075 * Returns: the a domain for a specific domain id.
2077 MonoDomain *
2078 mono_domain_get_by_id (gint32 domainid)
2080 MonoDomain * domain;
2082 mono_appdomains_lock ();
2083 if (domainid < appdomain_list_size)
2084 domain = appdomains_list [domainid];
2085 else
2086 domain = NULL;
2087 mono_appdomains_unlock ();
2089 return domain;
2092 gint32
2093 mono_domain_get_id (MonoDomain *domain)
2095 return domain->domain_id;
2099 * mono_domain_alloc:
2101 * LOCKING: Acquires the domain lock.
2103 gpointer
2104 mono_domain_alloc (MonoDomain *domain, guint size)
2106 gpointer res;
2108 mono_domain_lock (domain);
2109 mono_perfcounters->loader_bytes += size;
2110 res = mono_mempool_alloc (domain->mp, size);
2111 mono_domain_unlock (domain);
2113 return res;
2117 * mono_domain_alloc0:
2119 * LOCKING: Acquires the domain lock.
2121 gpointer
2122 mono_domain_alloc0 (MonoDomain *domain, guint size)
2124 gpointer res;
2126 mono_domain_lock (domain);
2127 mono_perfcounters->loader_bytes += size;
2128 res = mono_mempool_alloc0 (domain->mp, size);
2129 mono_domain_unlock (domain);
2131 return res;
2135 * mono_domain_code_reserve:
2137 * LOCKING: Acquires the domain lock.
2139 void*
2140 mono_domain_code_reserve (MonoDomain *domain, int size)
2142 gpointer res;
2144 mono_domain_lock (domain);
2145 res = mono_code_manager_reserve (domain->code_mp, size);
2146 mono_domain_unlock (domain);
2148 return res;
2152 * mono_domain_code_reserve_align:
2154 * LOCKING: Acquires the domain lock.
2156 void*
2157 mono_domain_code_reserve_align (MonoDomain *domain, int size, int alignment)
2159 gpointer res;
2161 mono_domain_lock (domain);
2162 res = mono_code_manager_reserve_align (domain->code_mp, size, alignment);
2163 mono_domain_unlock (domain);
2165 return res;
2169 * mono_domain_code_commit:
2171 * LOCKING: Acquires the domain lock.
2173 void
2174 mono_domain_code_commit (MonoDomain *domain, void *data, int size, int newsize)
2176 mono_domain_lock (domain);
2177 mono_code_manager_commit (domain->code_mp, data, size, newsize);
2178 mono_domain_unlock (domain);
2182 * mono_domain_code_foreach:
2183 * Iterate over the code thunks of the code manager of @domain.
2185 * The @func callback MUST not take any locks. If it really needs to, it must respect
2186 * the locking rules of the runtime: http://www.mono-project.com/Mono:Runtime:Documentation:ThreadSafety
2187 * LOCKING: Acquires the domain lock.
2190 void
2191 mono_domain_code_foreach (MonoDomain *domain, MonoCodeManagerFunc func, void *user_data)
2193 mono_domain_lock (domain);
2194 mono_code_manager_foreach (domain->code_mp, func, user_data);
2195 mono_domain_unlock (domain);
2199 void
2200 mono_context_set (MonoAppContext * new_context)
2202 SET_APPCONTEXT (new_context);
2205 MonoAppContext *
2206 mono_context_get (void)
2208 return GET_APPCONTEXT ();
2211 /* LOCKING: the caller holds the lock for this domain */
2212 void
2213 mono_domain_add_class_static_data (MonoDomain *domain, MonoClass *klass, gpointer data, guint32 *bitmap)
2215 /* The first entry in the array is the index of the next free slot
2216 * and the total size of the array
2218 int next;
2219 if (domain->static_data_array) {
2220 int size = GPOINTER_TO_INT (domain->static_data_array [1]);
2221 next = GPOINTER_TO_INT (domain->static_data_array [0]);
2222 if (next >= size) {
2223 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * (size * 2), NULL);
2224 memcpy (new_array, domain->static_data_array, sizeof (gpointer) * size);
2225 size *= 2;
2226 new_array [1] = GINT_TO_POINTER (size);
2227 mono_gc_free_fixed (domain->static_data_array);
2228 domain->static_data_array = new_array;
2230 } else {
2231 int size = 32;
2232 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * size, NULL);
2233 next = 2;
2234 new_array [0] = GINT_TO_POINTER (next);
2235 new_array [1] = GINT_TO_POINTER (size);
2236 domain->static_data_array = new_array;
2238 domain->static_data_array [next++] = data;
2239 domain->static_data_array [0] = GINT_TO_POINTER (next);
2242 MonoImage*
2243 mono_get_corlib (void)
2245 return mono_defaults.corlib;
2248 MonoClass*
2249 mono_get_object_class (void)
2251 return mono_defaults.object_class;
2254 MonoClass*
2255 mono_get_byte_class (void)
2257 return mono_defaults.byte_class;
2260 MonoClass*
2261 mono_get_void_class (void)
2263 return mono_defaults.void_class;
2266 MonoClass*
2267 mono_get_boolean_class (void)
2269 return mono_defaults.boolean_class;
2272 MonoClass*
2273 mono_get_sbyte_class (void)
2275 return mono_defaults.sbyte_class;
2278 MonoClass*
2279 mono_get_int16_class (void)
2281 return mono_defaults.int16_class;
2284 MonoClass*
2285 mono_get_uint16_class (void)
2287 return mono_defaults.uint16_class;
2290 MonoClass*
2291 mono_get_int32_class (void)
2293 return mono_defaults.int32_class;
2296 MonoClass*
2297 mono_get_uint32_class (void)
2299 return mono_defaults.uint32_class;
2302 MonoClass*
2303 mono_get_intptr_class (void)
2305 return mono_defaults.int_class;
2308 MonoClass*
2309 mono_get_uintptr_class (void)
2311 return mono_defaults.uint_class;
2314 MonoClass*
2315 mono_get_int64_class (void)
2317 return mono_defaults.int64_class;
2320 MonoClass*
2321 mono_get_uint64_class (void)
2323 return mono_defaults.uint64_class;
2326 MonoClass*
2327 mono_get_single_class (void)
2329 return mono_defaults.single_class;
2332 MonoClass*
2333 mono_get_double_class (void)
2335 return mono_defaults.double_class;
2338 MonoClass*
2339 mono_get_char_class (void)
2341 return mono_defaults.char_class;
2344 MonoClass*
2345 mono_get_string_class (void)
2347 return mono_defaults.string_class;
2350 MonoClass*
2351 mono_get_enum_class (void)
2353 return mono_defaults.enum_class;
2356 MonoClass*
2357 mono_get_array_class (void)
2359 return mono_defaults.array_class;
2362 MonoClass*
2363 mono_get_thread_class (void)
2365 return mono_defaults.thread_class;
2368 MonoClass*
2369 mono_get_exception_class (void)
2371 return mono_defaults.exception_class;
2375 static char* get_attribute_value (const gchar **attribute_names,
2376 const gchar **attribute_values,
2377 const char *att_name)
2379 int n;
2380 for (n=0; attribute_names[n] != NULL; n++) {
2381 if (strcmp (attribute_names[n], att_name) == 0)
2382 return g_strdup (attribute_values[n]);
2384 return NULL;
2387 static void start_element (GMarkupParseContext *context,
2388 const gchar *element_name,
2389 const gchar **attribute_names,
2390 const gchar **attribute_values,
2391 gpointer user_data,
2392 GError **error)
2394 AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2396 if (strcmp (element_name, "configuration") == 0) {
2397 app_config->configuration_count++;
2398 return;
2400 if (strcmp (element_name, "startup") == 0) {
2401 app_config->startup_count++;
2402 return;
2405 if (app_config->configuration_count != 1 || app_config->startup_count != 1)
2406 return;
2408 if (strcmp (element_name, "requiredRuntime") == 0) {
2409 app_config->required_runtime = get_attribute_value (attribute_names, attribute_values, "version");
2410 } else if (strcmp (element_name, "supportedRuntime") == 0) {
2411 char *version = get_attribute_value (attribute_names, attribute_values, "version");
2412 app_config->supported_runtimes = g_slist_append (app_config->supported_runtimes, version);
2416 static void end_element (GMarkupParseContext *context,
2417 const gchar *element_name,
2418 gpointer user_data,
2419 GError **error)
2421 AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2423 if (strcmp (element_name, "configuration") == 0) {
2424 app_config->configuration_count--;
2425 } else if (strcmp (element_name, "startup") == 0) {
2426 app_config->startup_count--;
2430 static const GMarkupParser
2431 mono_parser = {
2432 start_element,
2433 end_element,
2434 NULL,
2435 NULL,
2436 NULL
2439 static AppConfigInfo *
2440 app_config_parse (const char *exe_filename)
2442 AppConfigInfo *app_config;
2443 GMarkupParseContext *context;
2444 char *text;
2445 gsize len;
2446 const char *bundled_config;
2447 char *config_filename;
2449 bundled_config = mono_config_string_for_assembly_file (exe_filename);
2451 if (bundled_config) {
2452 text = g_strdup (bundled_config);
2453 len = strlen (text);
2454 } else {
2455 config_filename = g_strconcat (exe_filename, ".config", NULL);
2457 if (!g_file_get_contents (config_filename, &text, &len, NULL)) {
2458 g_free (config_filename);
2459 return NULL;
2461 g_free (config_filename);
2464 app_config = g_new0 (AppConfigInfo, 1);
2466 context = g_markup_parse_context_new (&mono_parser, 0, app_config, NULL);
2467 if (g_markup_parse_context_parse (context, text, len, NULL)) {
2468 g_markup_parse_context_end_parse (context, NULL);
2470 g_markup_parse_context_free (context);
2471 g_free (text);
2472 return app_config;
2475 static void
2476 app_config_free (AppConfigInfo* app_config)
2478 char *rt;
2479 GSList *list = app_config->supported_runtimes;
2480 while (list != NULL) {
2481 rt = (char*)list->data;
2482 g_free (rt);
2483 list = g_slist_next (list);
2485 g_slist_free (app_config->supported_runtimes);
2486 g_free (app_config->required_runtime);
2487 g_free (app_config);
2491 static const MonoRuntimeInfo*
2492 get_runtime_by_version (const char *version)
2494 int n;
2495 int max = G_N_ELEMENTS (supported_runtimes);
2497 for (n=0; n<max; n++) {
2498 if (strcmp (version, supported_runtimes[n].runtime_version) == 0)
2499 return &supported_runtimes[n];
2501 return NULL;
2504 static void
2505 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes)
2507 AppConfigInfo* app_config;
2508 char *version;
2509 const MonoRuntimeInfo* runtime = NULL;
2510 MonoImage *image = NULL;
2512 app_config = app_config_parse (exe_file);
2514 if (app_config != NULL) {
2515 /* Check supportedRuntime elements, if none is supported, fail.
2516 * If there are no such elements, look for a requiredRuntime element.
2518 if (app_config->supported_runtimes != NULL) {
2519 int n = 0;
2520 GSList *list = app_config->supported_runtimes;
2521 while (list != NULL) {
2522 version = (char*) list->data;
2523 runtime = get_runtime_by_version (version);
2524 if (runtime != NULL)
2525 runtimes [n++] = runtime;
2526 list = g_slist_next (list);
2528 runtimes [n] = NULL;
2529 app_config_free (app_config);
2530 return;
2533 /* Check the requiredRuntime element. This is for 1.0 apps only. */
2534 if (app_config->required_runtime != NULL) {
2535 runtimes [0] = get_runtime_by_version (app_config->required_runtime);
2536 runtimes [1] = NULL;
2537 app_config_free (app_config);
2538 return;
2540 app_config_free (app_config);
2543 /* Look for a runtime with the exact version */
2544 image = mono_assembly_open_from_bundle (exe_file, NULL, FALSE);
2546 if (image == NULL)
2547 image = mono_image_open (exe_file, NULL);
2549 if (image == NULL) {
2550 /* The image is wrong or the file was not found. In this case return
2551 * a default runtime and leave to the initialization method the work of
2552 * reporting the error.
2554 runtimes [0] = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
2555 runtimes [1] = NULL;
2556 return;
2559 *exe_image = image;
2561 runtimes [0] = get_runtime_by_version (image->version);
2562 runtimes [1] = NULL;
2567 * mono_get_runtime_info:
2569 * Returns: the version of the current runtime instance.
2571 const MonoRuntimeInfo*
2572 mono_get_runtime_info (void)
2574 return current_runtime;
2577 gchar *
2578 mono_debugger_check_runtime_version (const char *filename)
2580 const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
2581 const MonoRuntimeInfo *rinfo;
2582 MonoImage *image;
2584 get_runtimes_from_exe (filename, &image, runtimes);
2585 rinfo = runtimes [0];
2587 if (!rinfo)
2588 return g_strdup_printf ("Cannot get runtime version from assembly `%s'", filename);
2590 if (rinfo != current_runtime)
2591 return g_strdup_printf ("The Mono Debugger is currently using the `%s' runtime, but "
2592 "the assembly `%s' requires version `%s'", current_runtime->runtime_version,
2593 filename, rinfo->runtime_version);
2595 return NULL;
2599 * mono_framework_version:
2601 * Return the major version of the framework curently executing.
2604 mono_framework_version (void)
2606 return current_runtime->framework_version [0] - '0';