2010-05-13 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / metadata / domain.c
blob4629b351b84882113a15fdcbf13ef51c8cb1e042
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.30128","4.0", { {4,0,0,0}, {10,0,0,0} } },
134 {"v4.0.30319","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 if (!hp)
437 return NULL;
439 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
440 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
442 ji = NULL;
444 /* Maybe its an AOT module */
445 image = mono_jit_info_find_aot_module ((guint8*)addr);
446 if (image)
447 ji = jit_info_find_in_aot_func (domain, image, addr);
449 return ji;
452 static G_GNUC_UNUSED void
453 jit_info_table_check (MonoJitInfoTable *table)
455 int i;
457 for (i = 0; i < table->num_chunks; ++i) {
458 MonoJitInfoTableChunk *chunk = table->chunks [i];
459 int j;
461 g_assert (chunk->refcount > 0 /* && chunk->refcount <= 8 */);
462 if (chunk->refcount > 10)
463 printf("warning: chunk refcount is %d\n", chunk->refcount);
464 g_assert (chunk->num_elements <= MONO_JIT_INFO_TABLE_CHUNK_SIZE);
466 for (j = 0; j < chunk->num_elements; ++j) {
467 MonoJitInfo *this = chunk->data [j];
468 MonoJitInfo *next;
470 g_assert ((gint8*)this->code_start + this->code_size <= chunk->last_code_end);
472 if (j < chunk->num_elements - 1)
473 next = chunk->data [j + 1];
474 else if (i < table->num_chunks - 1) {
475 int k;
477 for (k = i + 1; k < table->num_chunks; ++k)
478 if (table->chunks [k]->num_elements > 0)
479 break;
481 if (k >= table->num_chunks)
482 return;
484 g_assert (table->chunks [k]->num_elements > 0);
485 next = table->chunks [k]->data [0];
486 } else
487 return;
489 g_assert ((gint8*)this->code_start + this->code_size <= (gint8*)next->code_start + next->code_size);
494 static MonoJitInfoTable*
495 jit_info_table_realloc (MonoJitInfoTable *old)
497 int i;
498 int num_elements = jit_info_table_num_elements (old);
499 int required_size;
500 int num_chunks;
501 int new_chunk, new_element;
502 MonoJitInfoTable *new;
504 /* number of needed places for elements needed */
505 required_size = (int)((long)num_elements * JIT_INFO_TABLE_FILL_RATIO_DENOM / JIT_INFO_TABLE_FILL_RATIO_NOM);
506 num_chunks = (required_size + MONO_JIT_INFO_TABLE_CHUNK_SIZE - 1) / MONO_JIT_INFO_TABLE_CHUNK_SIZE;
508 new = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*) * num_chunks);
509 new->domain = old->domain;
510 new->num_chunks = num_chunks;
512 for (i = 0; i < num_chunks; ++i)
513 new->chunks [i] = jit_info_table_new_chunk ();
515 new_chunk = 0;
516 new_element = 0;
517 for (i = 0; i < old->num_chunks; ++i) {
518 MonoJitInfoTableChunk *chunk = old->chunks [i];
519 int chunk_num_elements = chunk->num_elements;
520 int j;
522 for (j = 0; j < chunk_num_elements; ++j) {
523 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j])) {
524 g_assert (new_chunk < num_chunks);
525 new->chunks [new_chunk]->data [new_element] = chunk->data [j];
526 if (++new_element >= JIT_INFO_TABLE_FILLED_NUM_ELEMENTS) {
527 new->chunks [new_chunk]->num_elements = new_element;
528 ++new_chunk;
529 new_element = 0;
535 if (new_chunk < num_chunks) {
536 g_assert (new_chunk == num_chunks - 1);
537 new->chunks [new_chunk]->num_elements = new_element;
538 g_assert (new->chunks [new_chunk]->num_elements > 0);
541 for (i = 0; i < num_chunks; ++i) {
542 MonoJitInfoTableChunk *chunk = new->chunks [i];
543 MonoJitInfo *ji = chunk->data [chunk->num_elements - 1];
545 new->chunks [i]->last_code_end = (gint8*)ji->code_start + ji->code_size;
548 return new;
551 static void
552 jit_info_table_split_chunk (MonoJitInfoTableChunk *chunk, MonoJitInfoTableChunk **new1p, MonoJitInfoTableChunk **new2p)
554 MonoJitInfoTableChunk *new1 = jit_info_table_new_chunk ();
555 MonoJitInfoTableChunk *new2 = jit_info_table_new_chunk ();
557 g_assert (chunk->num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE);
559 new1->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE / 2;
560 new2->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE - new1->num_elements;
562 memcpy ((void*)new1->data, (void*)chunk->data, sizeof (MonoJitInfo*) * new1->num_elements);
563 memcpy ((void*)new2->data, (void*)(chunk->data + new1->num_elements), sizeof (MonoJitInfo*) * new2->num_elements);
565 new1->last_code_end = (gint8*)new1->data [new1->num_elements - 1]->code_start
566 + new1->data [new1->num_elements - 1]->code_size;
567 new2->last_code_end = (gint8*)new2->data [new2->num_elements - 1]->code_start
568 + new2->data [new2->num_elements - 1]->code_size;
570 *new1p = new1;
571 *new2p = new2;
574 static MonoJitInfoTable*
575 jit_info_table_copy_and_split_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
577 MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
578 + sizeof (MonoJitInfoTableChunk*) * (table->num_chunks + 1));
579 int i, j;
581 new_table->domain = table->domain;
582 new_table->num_chunks = table->num_chunks + 1;
584 j = 0;
585 for (i = 0; i < table->num_chunks; ++i) {
586 if (table->chunks [i] == chunk) {
587 jit_info_table_split_chunk (chunk, &new_table->chunks [j], &new_table->chunks [j + 1]);
588 j += 2;
589 } else {
590 new_table->chunks [j] = table->chunks [i];
591 ++new_table->chunks [j]->refcount;
592 ++j;
596 g_assert (j == new_table->num_chunks);
598 return new_table;
601 static MonoJitInfoTableChunk*
602 jit_info_table_purify_chunk (MonoJitInfoTableChunk *old)
604 MonoJitInfoTableChunk *new = jit_info_table_new_chunk ();
605 int i, j;
607 j = 0;
608 for (i = 0; i < old->num_elements; ++i) {
609 if (!IS_JIT_INFO_TOMBSTONE (old->data [i]))
610 new->data [j++] = old->data [i];
613 new->num_elements = j;
614 if (new->num_elements > 0)
615 new->last_code_end = (gint8*)new->data [j - 1]->code_start + new->data [j - 1]->code_size;
616 else
617 new->last_code_end = old->last_code_end;
619 return new;
622 static MonoJitInfoTable*
623 jit_info_table_copy_and_purify_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
625 MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
626 + sizeof (MonoJitInfoTableChunk*) * table->num_chunks);
627 int i, j;
629 new_table->domain = table->domain;
630 new_table->num_chunks = table->num_chunks;
632 j = 0;
633 for (i = 0; i < table->num_chunks; ++i) {
634 if (table->chunks [i] == chunk)
635 new_table->chunks [j++] = jit_info_table_purify_chunk (table->chunks [i]);
636 else {
637 new_table->chunks [j] = table->chunks [i];
638 ++new_table->chunks [j]->refcount;
639 ++j;
643 g_assert (j == new_table->num_chunks);
645 return new_table;
648 /* As we add an element to the table the case can arise that the chunk
649 * to which we need to add is already full. In that case we have to
650 * allocate a new table and do something about that chunk. We have
651 * several strategies:
653 * If the number of elements in the table is below the low watermark
654 * or above the high watermark, we reallocate the whole table.
655 * Otherwise we only concern ourselves with the overflowing chunk:
657 * If there are no tombstones in the chunk then we split the chunk in
658 * two, each half full.
660 * If the chunk does contain tombstones, we just make a new copy of
661 * the chunk without the tombstones, which will have room for at least
662 * the one element we have to add.
664 static MonoJitInfoTable*
665 jit_info_table_chunk_overflow (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
667 int num_elements = jit_info_table_num_elements (table);
668 int i;
670 if (num_elements < JIT_INFO_TABLE_LOW_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)
671 || num_elements > JIT_INFO_TABLE_HIGH_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)) {
672 //printf ("reallocing table\n");
673 return jit_info_table_realloc (table);
676 /* count the number of non-tombstone elements in the chunk */
677 num_elements = 0;
678 for (i = 0; i < chunk->num_elements; ++i) {
679 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [i]))
680 ++num_elements;
683 if (num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
684 //printf ("splitting chunk\n");
685 return jit_info_table_copy_and_split_chunk (table, chunk);
688 //printf ("purifying chunk\n");
689 return jit_info_table_copy_and_purify_chunk (table, chunk);
692 /* We add elements to the table by first making space for them by
693 * shifting the elements at the back to the right, one at a time.
694 * This results in duplicate entries during the process, but during
695 * all the time the table is in a sorted state. Also, when an element
696 * is replaced by another one, the element that replaces it has an end
697 * address that is equal to or lower than that of the replaced
698 * element. That property is necessary to guarantee that when
699 * searching for an element we end up at a position not higher than
700 * the one we're looking for (i.e. we either find the element directly
701 * or we end up to the left of it).
703 void
704 mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
706 MonoJitInfoTable *table;
707 int chunk_pos, pos;
708 MonoJitInfoTableChunk *chunk;
709 int num_elements;
710 int i;
712 g_assert (ji->method != NULL);
714 mono_domain_lock (domain);
716 ++mono_stats.jit_info_table_insert_count;
718 table = domain->jit_info_table;
720 restart:
721 chunk_pos = jit_info_table_index (table, (gint8*)ji->code_start + ji->code_size);
722 g_assert (chunk_pos < table->num_chunks);
723 chunk = table->chunks [chunk_pos];
725 if (chunk->num_elements >= MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
726 MonoJitInfoTable *new_table = jit_info_table_chunk_overflow (table, chunk);
728 /* Debugging code, should be removed. */
729 //jit_info_table_check (new_table);
731 domain->jit_info_table = new_table;
732 mono_memory_barrier ();
733 domain->num_jit_info_tables++;
734 mono_thread_hazardous_free_or_queue (table, (MonoHazardousFreeFunc)jit_info_table_free);
735 table = new_table;
737 goto restart;
740 /* Debugging code, should be removed. */
741 //jit_info_table_check (table);
743 num_elements = chunk->num_elements;
745 pos = jit_info_table_chunk_index (chunk, NULL, (gint8*)ji->code_start + ji->code_size);
747 /* First we need to size up the chunk by one, by copying the
748 last item, or inserting the first one, if the table is
749 empty. */
750 if (num_elements > 0)
751 chunk->data [num_elements] = chunk->data [num_elements - 1];
752 else
753 chunk->data [0] = ji;
754 mono_memory_write_barrier ();
755 chunk->num_elements = ++num_elements;
757 /* Shift the elements up one by one. */
758 for (i = num_elements - 2; i >= pos; --i) {
759 mono_memory_write_barrier ();
760 chunk->data [i + 1] = chunk->data [i];
763 /* Now we have room and can insert the new item. */
764 mono_memory_write_barrier ();
765 chunk->data [pos] = ji;
767 /* Set the high code end address chunk entry. */
768 chunk->last_code_end = (gint8*)chunk->data [chunk->num_elements - 1]->code_start
769 + chunk->data [chunk->num_elements - 1]->code_size;
771 /* Debugging code, should be removed. */
772 //jit_info_table_check (table);
774 mono_domain_unlock (domain);
777 static MonoJitInfo*
778 mono_jit_info_make_tombstone (MonoJitInfo *ji)
780 MonoJitInfo *tombstone = g_new0 (MonoJitInfo, 1);
782 tombstone->code_start = ji->code_start;
783 tombstone->code_size = ji->code_size;
784 tombstone->method = JIT_INFO_TOMBSTONE_MARKER;
786 return tombstone;
790 * LOCKING: domain lock
792 static void
793 mono_jit_info_free_or_queue (MonoDomain *domain, MonoJitInfo *ji)
795 if (domain->num_jit_info_tables <= 1) {
796 /* Can it actually happen that we only have one table
797 but ji is still hazardous? */
798 mono_thread_hazardous_free_or_queue (ji, g_free);
799 } else {
800 domain->jit_info_free_queue = g_slist_prepend (domain->jit_info_free_queue, ji);
804 void
805 mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
807 MonoJitInfoTable *table;
808 MonoJitInfoTableChunk *chunk;
809 gpointer start = ji->code_start;
810 int chunk_pos, pos;
812 mono_domain_lock (domain);
813 table = domain->jit_info_table;
815 ++mono_stats.jit_info_table_remove_count;
817 chunk_pos = jit_info_table_index (table, start);
818 g_assert (chunk_pos < table->num_chunks);
820 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], NULL, start);
822 do {
823 chunk = table->chunks [chunk_pos];
825 while (pos < chunk->num_elements) {
826 if (chunk->data [pos] == ji)
827 goto found;
829 g_assert (IS_JIT_INFO_TOMBSTONE (chunk->data [pos]));
830 g_assert ((guint8*)chunk->data [pos]->code_start + chunk->data [pos]->code_size
831 <= (guint8*)ji->code_start + ji->code_size);
833 ++pos;
836 ++chunk_pos;
837 pos = 0;
838 } while (chunk_pos < table->num_chunks);
840 found:
841 g_assert (chunk->data [pos] == ji);
843 chunk->data [pos] = mono_jit_info_make_tombstone (ji);
845 /* Debugging code, should be removed. */
846 //jit_info_table_check (table);
848 mono_jit_info_free_or_queue (domain, ji);
850 mono_domain_unlock (domain);
853 static MonoAotModuleInfoTable*
854 mono_aot_module_info_table_new (void)
856 return g_array_new (FALSE, FALSE, sizeof (gpointer));
859 static int
860 aot_info_table_index (MonoAotModuleInfoTable *table, char *addr)
862 int left = 0, right = table->len;
864 while (left < right) {
865 int pos = (left + right) / 2;
866 AotModuleInfo *ainfo = g_array_index (table, gpointer, pos);
867 char *start = ainfo->start;
868 char *end = ainfo->end;
870 if (addr < start)
871 right = pos;
872 else if (addr >= end)
873 left = pos + 1;
874 else
875 return pos;
878 return left;
881 void
882 mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
884 AotModuleInfo *ainfo = g_new0 (AotModuleInfo, 1);
885 int pos;
887 ainfo->image = image;
888 ainfo->start = start;
889 ainfo->end = end;
891 mono_appdomains_lock ();
893 if (!aot_modules)
894 aot_modules = mono_aot_module_info_table_new ();
896 pos = aot_info_table_index (aot_modules, start);
898 g_array_insert_val (aot_modules, pos, ainfo);
900 mono_appdomains_unlock ();
903 static MonoImage*
904 mono_jit_info_find_aot_module (guint8* addr)
906 guint left = 0, right;
908 if (!aot_modules)
909 return NULL;
911 mono_appdomains_lock ();
913 right = aot_modules->len;
914 while (left < right) {
915 guint pos = (left + right) / 2;
916 AotModuleInfo *ai = g_array_index (aot_modules, gpointer, pos);
918 if (addr < (guint8*)ai->start)
919 right = pos;
920 else if (addr >= (guint8*)ai->end)
921 left = pos + 1;
922 else {
923 mono_appdomains_unlock ();
924 return ai->image;
928 mono_appdomains_unlock ();
930 return NULL;
933 void
934 mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func)
936 jit_info_find_in_aot_func = func;
939 gpointer
940 mono_jit_info_get_code_start (MonoJitInfo* ji)
942 return ji->code_start;
946 mono_jit_info_get_code_size (MonoJitInfo* ji)
948 return ji->code_size;
951 MonoMethod*
952 mono_jit_info_get_method (MonoJitInfo* ji)
954 return ji->method;
957 static gpointer
958 jit_info_key_extract (gpointer value)
960 MonoJitInfo *info = (MonoJitInfo*)value;
962 return info->method;
965 static gpointer*
966 jit_info_next_value (gpointer value)
968 MonoJitInfo *info = (MonoJitInfo*)value;
970 return (gpointer*)&info->next_jit_code_hash;
973 void
974 mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
976 mono_internal_hash_table_init (jit_code_hash,
977 mono_aligned_addr_hash,
978 jit_info_key_extract,
979 jit_info_next_value);
982 MonoGenericJitInfo*
983 mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
985 if (ji->has_generic_jit_info)
986 return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
987 else
988 return NULL;
992 * mono_jit_info_get_generic_sharing_context:
993 * @ji: a jit info
995 * Returns the jit info's generic sharing context, or NULL if it
996 * doesn't have one.
998 MonoGenericSharingContext*
999 mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
1001 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
1003 if (gi)
1004 return gi->generic_sharing_context;
1005 else
1006 return NULL;
1010 * mono_jit_info_set_generic_sharing_context:
1011 * @ji: a jit info
1012 * @gsctx: a generic sharing context
1014 * Sets the jit info's generic sharing context. The jit info must
1015 * have memory allocated for the context.
1017 void
1018 mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
1020 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
1022 g_assert (gi);
1024 gi->generic_sharing_context = gsctx;
1027 MonoTryBlockHoleTableJitInfo*
1028 mono_jit_info_get_try_block_hole_table_info (MonoJitInfo *ji)
1030 if (ji->has_try_block_holes) {
1031 char *ptr = (char*)&ji->clauses [ji->num_clauses];
1032 if (ji->has_generic_jit_info)
1033 ptr += sizeof (MonoGenericJitInfo);
1034 return (MonoTryBlockHoleTableJitInfo*)ptr;
1035 } else {
1036 return NULL;
1039 void
1040 mono_install_create_domain_hook (MonoCreateDomainFunc func)
1042 create_domain_hook = func;
1045 void
1046 mono_install_free_domain_hook (MonoFreeDomainFunc func)
1048 free_domain_hook = func;
1052 * mono_string_equal:
1053 * @s1: First string to compare
1054 * @s2: Second string to compare
1056 * Returns FALSE if the strings differ.
1058 gboolean
1059 mono_string_equal (MonoString *s1, MonoString *s2)
1061 int l1 = mono_string_length (s1);
1062 int l2 = mono_string_length (s2);
1064 if (s1 == s2)
1065 return TRUE;
1066 if (l1 != l2)
1067 return FALSE;
1069 return memcmp (mono_string_chars (s1), mono_string_chars (s2), l1 * 2) == 0;
1073 * mono_string_hash:
1074 * @s: the string to hash
1076 * Returns the hash for the string.
1078 guint
1079 mono_string_hash (MonoString *s)
1081 const guint16 *p = mono_string_chars (s);
1082 int i, len = mono_string_length (s);
1083 guint h = 0;
1085 for (i = 0; i < len; i++) {
1086 h = (h << 5) - h + *p;
1087 p++;
1090 return h;
1093 static gboolean
1094 mono_ptrarray_equal (gpointer *s1, gpointer *s2)
1096 int len = GPOINTER_TO_INT (s1 [0]);
1097 if (len != GPOINTER_TO_INT (s2 [0]))
1098 return FALSE;
1100 return memcmp (s1 + 1, s2 + 1, len * sizeof(gpointer)) == 0;
1103 static guint
1104 mono_ptrarray_hash (gpointer *s)
1106 int i;
1107 int len = GPOINTER_TO_INT (s [0]);
1108 guint hash = 0;
1110 for (i = 1; i < len; i++)
1111 hash += GPOINTER_TO_UINT (s [i]);
1113 return hash;
1117 * Allocate an id for domain and set domain->domain_id.
1118 * LOCKING: must be called while holding appdomains_mutex.
1119 * We try to assign low numbers to the domain, so it can be used
1120 * as an index in data tables to lookup domain-specific info
1121 * with minimal memory overhead. We also try not to reuse the
1122 * same id too quickly (to help debugging).
1124 static int
1125 domain_id_alloc (MonoDomain *domain)
1127 int id = -1, i;
1128 if (!appdomains_list) {
1129 appdomain_list_size = 2;
1130 appdomains_list = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1132 for (i = appdomain_next; i < appdomain_list_size; ++i) {
1133 if (!appdomains_list [i]) {
1134 id = i;
1135 break;
1138 if (id == -1) {
1139 for (i = 0; i < appdomain_next; ++i) {
1140 if (!appdomains_list [i]) {
1141 id = i;
1142 break;
1146 if (id == -1) {
1147 MonoDomain **new_list;
1148 int new_size = appdomain_list_size * 2;
1149 if (new_size >= (1 << 16))
1150 g_assert_not_reached ();
1151 id = appdomain_list_size;
1152 new_list = mono_gc_alloc_fixed (new_size * sizeof (void*), NULL);
1153 memcpy (new_list, appdomains_list, appdomain_list_size * sizeof (void*));
1154 mono_gc_free_fixed (appdomains_list);
1155 appdomains_list = new_list;
1156 appdomain_list_size = new_size;
1158 domain->domain_id = id;
1159 appdomains_list [id] = domain;
1160 appdomain_next++;
1161 if (appdomain_next > appdomain_list_size)
1162 appdomain_next = 0;
1163 return id;
1166 static guint32 domain_gc_bitmap [sizeof(MonoDomain)/4/32 + 1];
1167 static gpointer domain_gc_desc = NULL;
1168 static guint32 domain_shadow_serial = 0L;
1170 MonoDomain *
1171 mono_domain_create (void)
1173 MonoDomain *domain;
1174 guint32 shadow_serial;
1176 mono_appdomains_lock ();
1177 shadow_serial = domain_shadow_serial++;
1179 if (!domain_gc_desc) {
1180 unsigned int i, bit = 0;
1181 for (i = G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_OBJECT); i < G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_GC_TRACKED); i += sizeof (gpointer)) {
1182 bit = i / sizeof (gpointer);
1183 domain_gc_bitmap [bit / 32] |= 1 << (bit % 32);
1185 domain_gc_desc = mono_gc_make_descr_from_bitmap ((gsize*)domain_gc_bitmap, bit + 1);
1187 mono_appdomains_unlock ();
1189 domain = mono_gc_alloc_fixed (sizeof (MonoDomain), domain_gc_desc);
1190 domain->shadow_serial = shadow_serial;
1191 domain->domain = NULL;
1192 domain->setup = NULL;
1193 domain->friendly_name = NULL;
1194 domain->search_path = NULL;
1196 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);
1198 mono_profiler_appdomain_event (domain, MONO_PROFILE_START_LOAD);
1200 domain->mp = mono_mempool_new ();
1201 domain->code_mp = mono_code_manager_new ();
1202 domain->env = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1203 domain->domain_assemblies = NULL;
1204 domain->assembly_bindings = NULL;
1205 domain->assembly_bindings_parsed = FALSE;
1206 domain->class_vtable_array = g_ptr_array_new ();
1207 domain->proxy_vtable_hash = g_hash_table_new ((GHashFunc)mono_ptrarray_hash, (GCompareFunc)mono_ptrarray_equal);
1208 domain->static_data_array = NULL;
1209 mono_jit_code_hash_init (&domain->jit_code_hash);
1210 domain->ldstr_table = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1211 domain->num_jit_info_tables = 1;
1212 domain->jit_info_table = jit_info_table_new (domain);
1213 domain->jit_info_free_queue = NULL;
1214 domain->finalizable_objects_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1215 #ifndef HAVE_SGEN_GC
1216 domain->track_resurrection_handles_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1217 #endif
1219 InitializeCriticalSection (&domain->lock);
1220 InitializeCriticalSection (&domain->assemblies_lock);
1221 InitializeCriticalSection (&domain->jit_code_hash_lock);
1222 InitializeCriticalSection (&domain->finalizable_objects_hash_lock);
1224 domain->method_rgctx_hash = NULL;
1226 mono_appdomains_lock ();
1227 domain_id_alloc (domain);
1228 mono_appdomains_unlock ();
1230 mono_perfcounters->loader_appdomains++;
1231 mono_perfcounters->loader_total_appdomains++;
1233 mono_debug_domain_create (domain);
1235 if (create_domain_hook)
1236 create_domain_hook (domain);
1238 mono_profiler_appdomain_loaded (domain, MONO_PROFILE_OK);
1240 return domain;
1244 * mono_init_internal:
1246 * Creates the initial application domain and initializes the mono_defaults
1247 * structure.
1248 * This function is guaranteed to not run any IL code.
1249 * If exe_filename is not NULL, the method will determine the required runtime
1250 * from the exe configuration file or the version PE field.
1251 * If runtime_version is not NULL, that runtime version will be used.
1252 * Either exe_filename or runtime_version must be provided.
1254 * Returns: the initial domain.
1256 static MonoDomain *
1257 mono_init_internal (const char *filename, const char *exe_filename, const char *runtime_version)
1259 static MonoDomain *domain = NULL;
1260 MonoAssembly *ass = NULL;
1261 MonoImageOpenStatus status = MONO_IMAGE_OK;
1262 const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
1263 int n;
1265 if (domain)
1266 g_assert_not_reached ();
1268 #ifdef HOST_WIN32
1269 /* Avoid system error message boxes. */
1270 SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1272 mono_load_coree (exe_filename);
1273 #endif
1275 mono_perfcounters_init ();
1277 mono_counters_register ("Max native code in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_size);
1278 mono_counters_register ("Max code space allocated in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_alloc);
1279 mono_counters_register ("Total code space allocated", MONO_COUNTER_INT|MONO_COUNTER_JIT, &total_domain_code_alloc);
1281 mono_gc_base_init ();
1283 appdomain_thread_id = TlsAlloc ();
1285 InitializeCriticalSection (&appdomains_mutex);
1287 mono_metadata_init ();
1288 mono_images_init ();
1289 mono_assemblies_init ();
1290 mono_classes_init ();
1291 mono_loader_init ();
1292 mono_reflection_init ();
1294 /* FIXME: When should we release this memory? */
1295 MONO_GC_REGISTER_ROOT (appdomains_list);
1297 domain = mono_domain_create ();
1298 mono_root_domain = domain;
1300 SET_APPDOMAIN (domain);
1302 /* Get a list of runtimes supported by the exe */
1303 if (exe_filename != NULL) {
1305 * This function will load the exe file as a MonoImage. We need to close it, but
1306 * that would mean it would be reloaded later. So instead, we save it to
1307 * exe_image, and close it during shutdown.
1309 get_runtimes_from_exe (exe_filename, &exe_image, runtimes);
1310 #ifdef HOST_WIN32
1311 if (!exe_image) {
1312 exe_image = mono_assembly_open_from_bundle (exe_filename, NULL, FALSE);
1313 if (!exe_image)
1314 exe_image = mono_image_open (exe_filename, NULL);
1316 mono_fixup_exe_image (exe_image);
1317 #endif
1318 } else if (runtime_version != NULL) {
1319 runtimes [0] = get_runtime_by_version (runtime_version);
1320 runtimes [1] = NULL;
1323 if (runtimes [0] == NULL) {
1324 const MonoRuntimeInfo *default_runtime = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
1325 runtimes [0] = default_runtime;
1326 runtimes [1] = NULL;
1327 g_print ("WARNING: The runtime version supported by this application is unavailable.\n");
1328 g_print ("Using default runtime: %s\n", default_runtime->runtime_version);
1331 /* The selected runtime will be the first one for which there is a mscrolib.dll */
1332 for (n = 0; runtimes [n] != NULL && ass == NULL; n++) {
1333 current_runtime = runtimes [n];
1334 ass = mono_assembly_load_corlib (current_runtime, &status);
1335 if (status != MONO_IMAGE_OK && status != MONO_IMAGE_ERROR_ERRNO)
1336 break;
1340 if ((status != MONO_IMAGE_OK) || (ass == NULL)) {
1341 switch (status){
1342 case MONO_IMAGE_ERROR_ERRNO: {
1343 char *corlib_file = g_build_filename (mono_assembly_getrootdir (), "mono", current_runtime->framework_version, "mscorlib.dll", NULL);
1344 g_print ("The assembly mscorlib.dll was not found or could not be loaded.\n");
1345 g_print ("It should have been installed in the `%s' directory.\n", corlib_file);
1346 g_free (corlib_file);
1347 break;
1349 case MONO_IMAGE_IMAGE_INVALID:
1350 g_print ("The file %s/mscorlib.dll is an invalid CIL image\n",
1351 mono_assembly_getrootdir ());
1352 break;
1353 case MONO_IMAGE_MISSING_ASSEMBLYREF:
1354 g_print ("Missing assembly reference in %s/mscorlib.dll\n",
1355 mono_assembly_getrootdir ());
1356 break;
1357 case MONO_IMAGE_OK:
1358 /* to suppress compiler warning */
1359 break;
1362 exit (1);
1364 mono_defaults.corlib = mono_assembly_get_image (ass);
1366 mono_defaults.object_class = mono_class_from_name (
1367 mono_defaults.corlib, "System", "Object");
1368 g_assert (mono_defaults.object_class != 0);
1370 mono_defaults.void_class = mono_class_from_name (
1371 mono_defaults.corlib, "System", "Void");
1372 g_assert (mono_defaults.void_class != 0);
1374 mono_defaults.boolean_class = mono_class_from_name (
1375 mono_defaults.corlib, "System", "Boolean");
1376 g_assert (mono_defaults.boolean_class != 0);
1378 mono_defaults.byte_class = mono_class_from_name (
1379 mono_defaults.corlib, "System", "Byte");
1380 g_assert (mono_defaults.byte_class != 0);
1382 mono_defaults.sbyte_class = mono_class_from_name (
1383 mono_defaults.corlib, "System", "SByte");
1384 g_assert (mono_defaults.sbyte_class != 0);
1386 mono_defaults.int16_class = mono_class_from_name (
1387 mono_defaults.corlib, "System", "Int16");
1388 g_assert (mono_defaults.int16_class != 0);
1390 mono_defaults.uint16_class = mono_class_from_name (
1391 mono_defaults.corlib, "System", "UInt16");
1392 g_assert (mono_defaults.uint16_class != 0);
1394 mono_defaults.int32_class = mono_class_from_name (
1395 mono_defaults.corlib, "System", "Int32");
1396 g_assert (mono_defaults.int32_class != 0);
1398 mono_defaults.uint32_class = mono_class_from_name (
1399 mono_defaults.corlib, "System", "UInt32");
1400 g_assert (mono_defaults.uint32_class != 0);
1402 mono_defaults.uint_class = mono_class_from_name (
1403 mono_defaults.corlib, "System", "UIntPtr");
1404 g_assert (mono_defaults.uint_class != 0);
1406 mono_defaults.int_class = mono_class_from_name (
1407 mono_defaults.corlib, "System", "IntPtr");
1408 g_assert (mono_defaults.int_class != 0);
1410 mono_defaults.int64_class = mono_class_from_name (
1411 mono_defaults.corlib, "System", "Int64");
1412 g_assert (mono_defaults.int64_class != 0);
1414 mono_defaults.uint64_class = mono_class_from_name (
1415 mono_defaults.corlib, "System", "UInt64");
1416 g_assert (mono_defaults.uint64_class != 0);
1418 mono_defaults.single_class = mono_class_from_name (
1419 mono_defaults.corlib, "System", "Single");
1420 g_assert (mono_defaults.single_class != 0);
1422 mono_defaults.double_class = mono_class_from_name (
1423 mono_defaults.corlib, "System", "Double");
1424 g_assert (mono_defaults.double_class != 0);
1426 mono_defaults.char_class = mono_class_from_name (
1427 mono_defaults.corlib, "System", "Char");
1428 g_assert (mono_defaults.char_class != 0);
1430 mono_defaults.string_class = mono_class_from_name (
1431 mono_defaults.corlib, "System", "String");
1432 g_assert (mono_defaults.string_class != 0);
1434 mono_defaults.enum_class = mono_class_from_name (
1435 mono_defaults.corlib, "System", "Enum");
1436 g_assert (mono_defaults.enum_class != 0);
1438 mono_defaults.array_class = mono_class_from_name (
1439 mono_defaults.corlib, "System", "Array");
1440 g_assert (mono_defaults.array_class != 0);
1442 mono_defaults.delegate_class = mono_class_from_name (
1443 mono_defaults.corlib, "System", "Delegate");
1444 g_assert (mono_defaults.delegate_class != 0 );
1446 mono_defaults.multicastdelegate_class = mono_class_from_name (
1447 mono_defaults.corlib, "System", "MulticastDelegate");
1448 g_assert (mono_defaults.multicastdelegate_class != 0 );
1450 mono_defaults.asyncresult_class = mono_class_from_name (
1451 mono_defaults.corlib, "System.Runtime.Remoting.Messaging",
1452 "AsyncResult");
1453 g_assert (mono_defaults.asyncresult_class != 0 );
1455 mono_defaults.manualresetevent_class = mono_class_from_name (
1456 mono_defaults.corlib, "System.Threading", "ManualResetEvent");
1457 g_assert (mono_defaults.manualresetevent_class != 0 );
1459 mono_defaults.typehandle_class = mono_class_from_name (
1460 mono_defaults.corlib, "System", "RuntimeTypeHandle");
1461 g_assert (mono_defaults.typehandle_class != 0);
1463 mono_defaults.methodhandle_class = mono_class_from_name (
1464 mono_defaults.corlib, "System", "RuntimeMethodHandle");
1465 g_assert (mono_defaults.methodhandle_class != 0);
1467 mono_defaults.fieldhandle_class = mono_class_from_name (
1468 mono_defaults.corlib, "System", "RuntimeFieldHandle");
1469 g_assert (mono_defaults.fieldhandle_class != 0);
1471 mono_defaults.systemtype_class = mono_class_from_name (
1472 mono_defaults.corlib, "System", "Type");
1473 g_assert (mono_defaults.systemtype_class != 0);
1475 mono_defaults.monotype_class = mono_class_from_name (
1476 mono_defaults.corlib, "System", "MonoType");
1477 g_assert (mono_defaults.monotype_class != 0);
1479 mono_defaults.exception_class = mono_class_from_name (
1480 mono_defaults.corlib, "System", "Exception");
1481 g_assert (mono_defaults.exception_class != 0);
1483 mono_defaults.threadabortexception_class = mono_class_from_name (
1484 mono_defaults.corlib, "System.Threading", "ThreadAbortException");
1485 g_assert (mono_defaults.threadabortexception_class != 0);
1487 mono_defaults.thread_class = mono_class_from_name (
1488 mono_defaults.corlib, "System.Threading", "Thread");
1489 g_assert (mono_defaults.thread_class != 0);
1491 mono_defaults.internal_thread_class = mono_class_from_name (
1492 mono_defaults.corlib, "System.Threading", "InternalThread");
1493 if (!mono_defaults.internal_thread_class) {
1494 /* This can happen with an old mscorlib */
1495 fprintf (stderr, "Corlib too old for this runtime.\n");
1496 fprintf (stderr, "Loaded from: %s\n",
1497 mono_defaults.corlib? mono_image_get_filename (mono_defaults.corlib): "unknown");
1498 exit (1);
1501 mono_defaults.appdomain_class = mono_class_from_name (
1502 mono_defaults.corlib, "System", "AppDomain");
1503 g_assert (mono_defaults.appdomain_class != 0);
1505 mono_defaults.transparent_proxy_class = mono_class_from_name (
1506 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "TransparentProxy");
1507 g_assert (mono_defaults.transparent_proxy_class != 0);
1509 mono_defaults.real_proxy_class = mono_class_from_name (
1510 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "RealProxy");
1511 g_assert (mono_defaults.real_proxy_class != 0);
1513 mono_defaults.mono_method_message_class = mono_class_from_name (
1514 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", "MonoMethodMessage");
1515 g_assert (mono_defaults.mono_method_message_class != 0);
1517 mono_defaults.field_info_class = mono_class_from_name (
1518 mono_defaults.corlib, "System.Reflection", "FieldInfo");
1519 g_assert (mono_defaults.field_info_class != 0);
1521 mono_defaults.method_info_class = mono_class_from_name (
1522 mono_defaults.corlib, "System.Reflection", "MethodInfo");
1523 g_assert (mono_defaults.method_info_class != 0);
1525 mono_defaults.stringbuilder_class = mono_class_from_name (
1526 mono_defaults.corlib, "System.Text", "StringBuilder");
1527 g_assert (mono_defaults.stringbuilder_class != 0);
1529 mono_defaults.math_class = mono_class_from_name (
1530 mono_defaults.corlib, "System", "Math");
1531 g_assert (mono_defaults.math_class != 0);
1533 mono_defaults.stack_frame_class = mono_class_from_name (
1534 mono_defaults.corlib, "System.Diagnostics", "StackFrame");
1535 g_assert (mono_defaults.stack_frame_class != 0);
1537 mono_defaults.stack_trace_class = mono_class_from_name (
1538 mono_defaults.corlib, "System.Diagnostics", "StackTrace");
1539 g_assert (mono_defaults.stack_trace_class != 0);
1541 mono_defaults.marshal_class = mono_class_from_name (
1542 mono_defaults.corlib, "System.Runtime.InteropServices", "Marshal");
1543 g_assert (mono_defaults.marshal_class != 0);
1545 mono_defaults.iserializeable_class = mono_class_from_name (
1546 mono_defaults.corlib, "System.Runtime.Serialization", "ISerializable");
1547 g_assert (mono_defaults.iserializeable_class != 0);
1549 mono_defaults.serializationinfo_class = mono_class_from_name (
1550 mono_defaults.corlib, "System.Runtime.Serialization", "SerializationInfo");
1551 g_assert (mono_defaults.serializationinfo_class != 0);
1553 mono_defaults.streamingcontext_class = mono_class_from_name (
1554 mono_defaults.corlib, "System.Runtime.Serialization", "StreamingContext");
1555 g_assert (mono_defaults.streamingcontext_class != 0);
1557 mono_defaults.typed_reference_class = mono_class_from_name (
1558 mono_defaults.corlib, "System", "TypedReference");
1559 g_assert (mono_defaults.typed_reference_class != 0);
1561 mono_defaults.argumenthandle_class = mono_class_from_name (
1562 mono_defaults.corlib, "System", "RuntimeArgumentHandle");
1563 g_assert (mono_defaults.argumenthandle_class != 0);
1565 mono_defaults.marshalbyrefobject_class = mono_class_from_name (
1566 mono_defaults.corlib, "System", "MarshalByRefObject");
1567 g_assert (mono_defaults.marshalbyrefobject_class != 0);
1569 mono_defaults.monitor_class = mono_class_from_name (
1570 mono_defaults.corlib, "System.Threading", "Monitor");
1571 g_assert (mono_defaults.monitor_class != 0);
1573 mono_defaults.iremotingtypeinfo_class = mono_class_from_name (
1574 mono_defaults.corlib, "System.Runtime.Remoting", "IRemotingTypeInfo");
1575 g_assert (mono_defaults.iremotingtypeinfo_class != 0);
1577 mono_defaults.runtimesecurityframe_class = mono_class_from_name (
1578 mono_defaults.corlib, "System.Security", "RuntimeSecurityFrame");
1580 mono_defaults.executioncontext_class = mono_class_from_name (
1581 mono_defaults.corlib, "System.Threading", "ExecutionContext");
1583 mono_defaults.internals_visible_class = mono_class_from_name (
1584 mono_defaults.corlib, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute");
1586 mono_defaults.critical_finalizer_object = mono_class_from_name (
1587 mono_defaults.corlib, "System.Runtime.ConstrainedExecution", "CriticalFinalizerObject");
1590 * mscorlib needs a little help, only now it can load its friends list (after we have
1591 * loaded the InternalsVisibleToAttribute), load it now
1593 mono_assembly_load_friends (ass);
1595 mono_defaults.safehandle_class = mono_class_from_name (
1596 mono_defaults.corlib, "System.Runtime.InteropServices", "SafeHandle");
1598 mono_defaults.handleref_class = mono_class_from_name (
1599 mono_defaults.corlib, "System.Runtime.InteropServices", "HandleRef");
1601 mono_defaults.attribute_class = mono_class_from_name (
1602 mono_defaults.corlib, "System", "Attribute");
1604 mono_defaults.customattribute_data_class = mono_class_from_name (
1605 mono_defaults.corlib, "System.Reflection", "CustomAttributeData");
1607 /* these are initialized lazily when COM features are used */
1608 mono_defaults.variant_class = NULL;
1609 mono_defaults.com_object_class = NULL;
1610 mono_defaults.com_interop_proxy_class = NULL;
1611 mono_defaults.iunknown_class = NULL;
1612 mono_defaults.idispatch_class = NULL;
1615 * Note that mono_defaults.generic_*_class is only non-NULL if we're
1616 * using the 2.0 corlib.
1618 mono_class_init (mono_defaults.array_class);
1619 mono_defaults.generic_nullable_class = mono_class_from_name (
1620 mono_defaults.corlib, "System", "Nullable`1");
1621 mono_defaults.generic_ilist_class = mono_class_from_name (
1622 mono_defaults.corlib, "System.Collections.Generic", "IList`1");
1624 domain->friendly_name = g_path_get_basename (filename);
1626 _mono_debug_init_corlib (domain);
1628 return domain;
1632 * mono_init:
1634 * Creates the initial application domain and initializes the mono_defaults
1635 * structure.
1636 * This function is guaranteed to not run any IL code.
1637 * The runtime is initialized using the default runtime version.
1639 * Returns: the initial domain.
1641 MonoDomain *
1642 mono_init (const char *domain_name)
1644 return mono_init_internal (domain_name, NULL, DEFAULT_RUNTIME_VERSION);
1648 * mono_init_from_assembly:
1649 * @domain_name: name to give to the initial domain
1650 * @filename: filename to load on startup
1652 * Used by the runtime, users should use mono_jit_init instead.
1654 * Creates the initial application domain and initializes the mono_defaults
1655 * structure.
1656 * This function is guaranteed to not run any IL code.
1657 * The runtime is initialized using the runtime version required by the
1658 * provided executable. The version is determined by looking at the exe
1659 * configuration file and the version PE field)
1661 * Returns: the initial domain.
1663 MonoDomain *
1664 mono_init_from_assembly (const char *domain_name, const char *filename)
1666 return mono_init_internal (domain_name, filename, NULL);
1670 * mono_init_version:
1672 * Used by the runtime, users should use mono_jit_init instead.
1674 * Creates the initial application domain and initializes the mono_defaults
1675 * structure.
1677 * This function is guaranteed to not run any IL code.
1678 * The runtime is initialized using the provided rutime version.
1680 * Returns: the initial domain.
1682 MonoDomain *
1683 mono_init_version (const char *domain_name, const char *version)
1685 return mono_init_internal (domain_name, NULL, version);
1689 * mono_init_com_types:
1691 * Initializes all types needed for COM Interop in mono_defaults structure.
1693 void
1694 mono_init_com_types (void)
1696 static gboolean initialized = FALSE;
1698 if (initialized)
1699 return;
1701 /* FIXME: do I need some threading protection here */
1703 g_assert (mono_defaults.corlib);
1705 mono_defaults.variant_class = mono_class_from_name (
1706 mono_defaults.corlib, "System", "Variant");
1707 g_assert (mono_defaults.variant_class != 0);
1709 mono_defaults.com_object_class = mono_class_from_name (
1710 mono_defaults.corlib, "System", "__ComObject");
1711 g_assert (mono_defaults.com_object_class != 0);
1713 mono_defaults.com_interop_proxy_class = mono_class_from_name (
1714 mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
1715 g_assert (mono_defaults.com_interop_proxy_class != 0);
1717 mono_defaults.iunknown_class = mono_class_from_name (
1718 mono_defaults.corlib, "Mono.Interop", "IUnknown");
1719 g_assert (mono_defaults.iunknown_class != 0);
1721 mono_defaults.idispatch_class = mono_class_from_name (
1722 mono_defaults.corlib, "Mono.Interop", "IDispatch");
1723 g_assert (mono_defaults.idispatch_class != 0);
1725 initialized = TRUE;
1729 * mono_cleanup:
1731 * Cleans up all metadata modules.
1733 void
1734 mono_cleanup (void)
1736 mono_close_exe_image ();
1738 mono_loader_cleanup ();
1739 mono_classes_cleanup ();
1740 mono_assemblies_cleanup ();
1741 mono_images_cleanup ();
1742 mono_debug_cleanup ();
1743 mono_metadata_cleanup ();
1745 TlsFree (appdomain_thread_id);
1746 DeleteCriticalSection (&appdomains_mutex);
1749 void
1750 mono_close_exe_image (void)
1752 if (exe_image)
1753 mono_image_close (exe_image);
1757 * mono_get_root_domain:
1759 * The root AppDomain is the initial domain created by the runtime when it is
1760 * initialized. Programs execute on this AppDomain, but can create new ones
1761 * later. Currently there is no unmanaged API to create new AppDomains, this
1762 * must be done from managed code.
1764 * Returns: the root appdomain, to obtain the current domain, use mono_domain_get ()
1766 MonoDomain*
1767 mono_get_root_domain (void)
1769 return mono_root_domain;
1773 * mono_domain_get:
1775 * Returns: the current domain, to obtain the root domain use
1776 * mono_get_root_domain().
1778 MonoDomain *
1779 mono_domain_get ()
1781 return GET_APPDOMAIN ();
1784 void
1785 mono_domain_unset (void)
1787 SET_APPDOMAIN (NULL);
1790 void
1791 mono_domain_set_internal_with_options (MonoDomain *domain, gboolean migrate_exception)
1793 MonoInternalThread *thread;
1795 if (mono_domain_get () == domain)
1796 return;
1798 SET_APPDOMAIN (domain);
1799 SET_APPCONTEXT (domain->default_context);
1801 if (migrate_exception) {
1802 thread = mono_thread_internal_current ();
1803 if (!thread->abort_exc)
1804 return;
1806 g_assert (thread->abort_exc->object.vtable->domain != domain);
1807 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
1808 g_assert (thread->abort_exc->object.vtable->domain == domain);
1813 * mono_domain_set_internal:
1814 * @domain: the new domain
1816 * Sets the current domain to @domain.
1818 void
1819 mono_domain_set_internal (MonoDomain *domain)
1821 mono_domain_set_internal_with_options (domain, TRUE);
1824 void
1825 mono_domain_foreach (MonoDomainFunc func, gpointer user_data)
1827 int i, size;
1828 MonoDomain **copy;
1831 * Create a copy of the data to avoid calling the user callback
1832 * inside the lock because that could lead to deadlocks.
1833 * We can do this because this function is not perf. critical.
1835 mono_appdomains_lock ();
1836 size = appdomain_list_size;
1837 copy = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1838 memcpy (copy, appdomains_list, appdomain_list_size * sizeof (void*));
1839 mono_appdomains_unlock ();
1841 for (i = 0; i < size; ++i) {
1842 if (copy [i])
1843 func (copy [i], user_data);
1846 mono_gc_free_fixed (copy);
1850 * mono_domain_assembly_open:
1851 * @domain: the application domain
1852 * @name: file name of the assembly
1854 * fixme: maybe we should integrate this with mono_assembly_open ??
1856 MonoAssembly *
1857 mono_domain_assembly_open (MonoDomain *domain, const char *name)
1859 MonoDomain *current;
1860 MonoAssembly *ass;
1861 GSList *tmp;
1863 mono_domain_assemblies_lock (domain);
1864 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1865 ass = tmp->data;
1866 if (strcmp (name, ass->aname.name) == 0) {
1867 mono_domain_assemblies_unlock (domain);
1868 return ass;
1871 mono_domain_assemblies_unlock (domain);
1873 if (domain != mono_domain_get ()) {
1874 current = mono_domain_get ();
1876 mono_domain_set (domain, FALSE);
1877 ass = mono_assembly_open (name, NULL);
1878 mono_domain_set (current, FALSE);
1879 } else {
1880 ass = mono_assembly_open (name, NULL);
1883 return ass;
1886 #ifndef HAVE_SGEN_GC
1887 static void
1888 free_slist (gpointer key, gpointer value, gpointer user_data)
1890 g_slist_free (value);
1892 #endif
1894 #if HAVE_SGEN_GC
1895 static void
1896 unregister_vtable_reflection_type (MonoVTable *vtable)
1898 MonoObject *type = vtable->type;
1900 if (type->vtable->klass != mono_defaults.monotype_class)
1901 mono_gc_deregister_root ((char*)&vtable->type);
1903 #endif
1905 void
1906 mono_domain_free (MonoDomain *domain, gboolean force)
1908 int code_size, code_alloc;
1909 GSList *tmp;
1910 if ((domain == mono_root_domain) && !force) {
1911 g_warning ("cant unload root domain");
1912 return;
1915 if (mono_dont_free_domains)
1916 return;
1918 mono_profiler_appdomain_event (domain, MONO_PROFILE_START_UNLOAD);
1920 mono_debug_domain_unload (domain);
1922 mono_appdomains_lock ();
1923 appdomains_list [domain->domain_id] = NULL;
1924 mono_appdomains_unlock ();
1926 /* must do this early as it accesses fields and types */
1927 if (domain->special_static_fields) {
1928 mono_alloc_special_static_data_free (domain->special_static_fields);
1929 g_hash_table_destroy (domain->special_static_fields);
1930 domain->special_static_fields = NULL;
1934 * We must destroy all these hash tables here because they
1935 * contain references to managed objects belonging to the
1936 * domain. Once we let the GC clear the domain there must be
1937 * no more such references, or we'll crash if a collection
1938 * occurs.
1940 mono_g_hash_table_destroy (domain->ldstr_table);
1941 domain->ldstr_table = NULL;
1943 mono_g_hash_table_destroy (domain->env);
1944 domain->env = NULL;
1946 mono_reflection_cleanup_domain (domain);
1948 if (domain->type_hash) {
1949 mono_g_hash_table_destroy (domain->type_hash);
1950 domain->type_hash = NULL;
1952 if (domain->type_init_exception_hash) {
1953 mono_g_hash_table_destroy (domain->type_init_exception_hash);
1954 domain->type_init_exception_hash = NULL;
1957 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1958 MonoAssembly *ass = tmp->data;
1959 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);
1960 if (!mono_assembly_close_except_image_pools (ass))
1961 tmp->data = NULL;
1964 #if HAVE_SGEN_GC
1965 if (domain->class_vtable_array) {
1966 int i;
1967 for (i = 0; i < domain->class_vtable_array->len; ++i)
1968 unregister_vtable_reflection_type (g_ptr_array_index (domain->class_vtable_array, i));
1970 #endif
1972 mono_gc_clear_domain (domain);
1974 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1975 MonoAssembly *ass = tmp->data;
1976 if (ass)
1977 mono_assembly_close_finish (ass);
1979 g_slist_free (domain->domain_assemblies);
1980 domain->domain_assemblies = NULL;
1983 * Send this after the assemblies have been unloaded and the domain is still in a
1984 * usable state.
1986 mono_profiler_appdomain_event (domain, MONO_PROFILE_END_UNLOAD);
1988 if (free_domain_hook)
1989 free_domain_hook (domain);
1991 /* FIXME: free delegate_hash_table when it's used */
1992 if (domain->search_path) {
1993 g_strfreev (domain->search_path);
1994 domain->search_path = NULL;
1996 domain->create_proxy_for_type_method = NULL;
1997 domain->private_invoke_method = NULL;
1998 domain->default_context = NULL;
1999 domain->out_of_memory_ex = NULL;
2000 domain->null_reference_ex = NULL;
2001 domain->stack_overflow_ex = NULL;
2002 domain->ephemeron_tombstone = NULL;
2003 domain->entry_assembly = NULL;
2005 g_free (domain->friendly_name);
2006 domain->friendly_name = NULL;
2007 g_ptr_array_free (domain->class_vtable_array, TRUE);
2008 domain->class_vtable_array = NULL;
2009 g_hash_table_destroy (domain->proxy_vtable_hash);
2010 domain->proxy_vtable_hash = NULL;
2011 if (domain->static_data_array) {
2012 mono_gc_free_fixed (domain->static_data_array);
2013 domain->static_data_array = NULL;
2015 mono_internal_hash_table_destroy (&domain->jit_code_hash);
2018 * There might still be jit info tables of this domain which
2019 * are not freed. Since the domain cannot be in use anymore,
2020 * this will free them.
2022 mono_thread_hazardous_try_free_all ();
2023 g_assert (domain->num_jit_info_tables == 1);
2024 jit_info_table_free (domain->jit_info_table);
2025 domain->jit_info_table = NULL;
2026 g_assert (!domain->jit_info_free_queue);
2028 /* collect statistics */
2029 code_alloc = mono_code_manager_size (domain->code_mp, &code_size);
2030 total_domain_code_alloc += code_alloc;
2031 max_domain_code_alloc = MAX (max_domain_code_alloc, code_alloc);
2032 max_domain_code_size = MAX (max_domain_code_size, code_size);
2034 #ifdef DEBUG_DOMAIN_UNLOAD
2035 mono_mempool_invalidate (domain->mp);
2036 mono_code_manager_invalidate (domain->code_mp);
2037 #else
2038 mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (domain->mp);
2039 mono_mempool_destroy (domain->mp);
2040 domain->mp = NULL;
2041 mono_code_manager_destroy (domain->code_mp);
2042 domain->code_mp = NULL;
2043 #endif
2045 g_hash_table_destroy (domain->finalizable_objects_hash);
2046 domain->finalizable_objects_hash = NULL;
2047 #ifndef HAVE_SGEN_GC
2048 if (domain->track_resurrection_objects_hash) {
2049 g_hash_table_foreach (domain->track_resurrection_objects_hash, free_slist, NULL);
2050 g_hash_table_destroy (domain->track_resurrection_objects_hash);
2052 if (domain->track_resurrection_handles_hash)
2053 g_hash_table_destroy (domain->track_resurrection_handles_hash);
2054 #endif
2055 if (domain->method_rgctx_hash) {
2056 g_hash_table_destroy (domain->method_rgctx_hash);
2057 domain->method_rgctx_hash = NULL;
2059 if (domain->generic_virtual_cases) {
2060 g_hash_table_destroy (domain->generic_virtual_cases);
2061 domain->generic_virtual_cases = NULL;
2064 DeleteCriticalSection (&domain->finalizable_objects_hash_lock);
2065 DeleteCriticalSection (&domain->assemblies_lock);
2066 DeleteCriticalSection (&domain->jit_code_hash_lock);
2067 DeleteCriticalSection (&domain->lock);
2068 domain->setup = NULL;
2070 mono_gc_deregister_root ((char*)&(domain->MONO_DOMAIN_FIRST_GC_TRACKED));
2072 /* FIXME: anything else required ? */
2074 mono_gc_free_fixed (domain);
2076 mono_perfcounters->loader_appdomains--;
2078 if ((domain == mono_root_domain))
2079 mono_root_domain = NULL;
2083 * mono_domain_get_id:
2084 * @domainid: the ID
2086 * Returns: the a domain for a specific domain id.
2088 MonoDomain *
2089 mono_domain_get_by_id (gint32 domainid)
2091 MonoDomain * domain;
2093 mono_appdomains_lock ();
2094 if (domainid < appdomain_list_size)
2095 domain = appdomains_list [domainid];
2096 else
2097 domain = NULL;
2098 mono_appdomains_unlock ();
2100 return domain;
2103 gint32
2104 mono_domain_get_id (MonoDomain *domain)
2106 return domain->domain_id;
2110 * mono_domain_alloc:
2112 * LOCKING: Acquires the domain lock.
2114 gpointer
2115 mono_domain_alloc (MonoDomain *domain, guint size)
2117 gpointer res;
2119 mono_domain_lock (domain);
2120 mono_perfcounters->loader_bytes += size;
2121 res = mono_mempool_alloc (domain->mp, size);
2122 mono_domain_unlock (domain);
2124 return res;
2128 * mono_domain_alloc0:
2130 * LOCKING: Acquires the domain lock.
2132 gpointer
2133 mono_domain_alloc0 (MonoDomain *domain, guint size)
2135 gpointer res;
2137 mono_domain_lock (domain);
2138 mono_perfcounters->loader_bytes += size;
2139 res = mono_mempool_alloc0 (domain->mp, size);
2140 mono_domain_unlock (domain);
2142 return res;
2146 * mono_domain_code_reserve:
2148 * LOCKING: Acquires the domain lock.
2150 void*
2151 mono_domain_code_reserve (MonoDomain *domain, int size)
2153 gpointer res;
2155 mono_domain_lock (domain);
2156 res = mono_code_manager_reserve (domain->code_mp, size);
2157 mono_domain_unlock (domain);
2159 return res;
2163 * mono_domain_code_reserve_align:
2165 * LOCKING: Acquires the domain lock.
2167 void*
2168 mono_domain_code_reserve_align (MonoDomain *domain, int size, int alignment)
2170 gpointer res;
2172 mono_domain_lock (domain);
2173 res = mono_code_manager_reserve_align (domain->code_mp, size, alignment);
2174 mono_domain_unlock (domain);
2176 return res;
2180 * mono_domain_code_commit:
2182 * LOCKING: Acquires the domain lock.
2184 void
2185 mono_domain_code_commit (MonoDomain *domain, void *data, int size, int newsize)
2187 mono_domain_lock (domain);
2188 mono_code_manager_commit (domain->code_mp, data, size, newsize);
2189 mono_domain_unlock (domain);
2193 * mono_domain_code_foreach:
2194 * Iterate over the code thunks of the code manager of @domain.
2196 * The @func callback MUST not take any locks. If it really needs to, it must respect
2197 * the locking rules of the runtime: http://www.mono-project.com/Mono:Runtime:Documentation:ThreadSafety
2198 * LOCKING: Acquires the domain lock.
2201 void
2202 mono_domain_code_foreach (MonoDomain *domain, MonoCodeManagerFunc func, void *user_data)
2204 mono_domain_lock (domain);
2205 mono_code_manager_foreach (domain->code_mp, func, user_data);
2206 mono_domain_unlock (domain);
2210 void
2211 mono_context_set (MonoAppContext * new_context)
2213 SET_APPCONTEXT (new_context);
2216 MonoAppContext *
2217 mono_context_get (void)
2219 return GET_APPCONTEXT ();
2222 /* LOCKING: the caller holds the lock for this domain */
2223 void
2224 mono_domain_add_class_static_data (MonoDomain *domain, MonoClass *klass, gpointer data, guint32 *bitmap)
2226 /* The first entry in the array is the index of the next free slot
2227 * and the total size of the array
2229 int next;
2230 if (domain->static_data_array) {
2231 int size = GPOINTER_TO_INT (domain->static_data_array [1]);
2232 next = GPOINTER_TO_INT (domain->static_data_array [0]);
2233 if (next >= size) {
2234 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * (size * 2), NULL);
2235 memcpy (new_array, domain->static_data_array, sizeof (gpointer) * size);
2236 size *= 2;
2237 new_array [1] = GINT_TO_POINTER (size);
2238 mono_gc_free_fixed (domain->static_data_array);
2239 domain->static_data_array = new_array;
2241 } else {
2242 int size = 32;
2243 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * size, NULL);
2244 next = 2;
2245 new_array [0] = GINT_TO_POINTER (next);
2246 new_array [1] = GINT_TO_POINTER (size);
2247 domain->static_data_array = new_array;
2249 domain->static_data_array [next++] = data;
2250 domain->static_data_array [0] = GINT_TO_POINTER (next);
2253 MonoImage*
2254 mono_get_corlib (void)
2256 return mono_defaults.corlib;
2259 MonoClass*
2260 mono_get_object_class (void)
2262 return mono_defaults.object_class;
2265 MonoClass*
2266 mono_get_byte_class (void)
2268 return mono_defaults.byte_class;
2271 MonoClass*
2272 mono_get_void_class (void)
2274 return mono_defaults.void_class;
2277 MonoClass*
2278 mono_get_boolean_class (void)
2280 return mono_defaults.boolean_class;
2283 MonoClass*
2284 mono_get_sbyte_class (void)
2286 return mono_defaults.sbyte_class;
2289 MonoClass*
2290 mono_get_int16_class (void)
2292 return mono_defaults.int16_class;
2295 MonoClass*
2296 mono_get_uint16_class (void)
2298 return mono_defaults.uint16_class;
2301 MonoClass*
2302 mono_get_int32_class (void)
2304 return mono_defaults.int32_class;
2307 MonoClass*
2308 mono_get_uint32_class (void)
2310 return mono_defaults.uint32_class;
2313 MonoClass*
2314 mono_get_intptr_class (void)
2316 return mono_defaults.int_class;
2319 MonoClass*
2320 mono_get_uintptr_class (void)
2322 return mono_defaults.uint_class;
2325 MonoClass*
2326 mono_get_int64_class (void)
2328 return mono_defaults.int64_class;
2331 MonoClass*
2332 mono_get_uint64_class (void)
2334 return mono_defaults.uint64_class;
2337 MonoClass*
2338 mono_get_single_class (void)
2340 return mono_defaults.single_class;
2343 MonoClass*
2344 mono_get_double_class (void)
2346 return mono_defaults.double_class;
2349 MonoClass*
2350 mono_get_char_class (void)
2352 return mono_defaults.char_class;
2355 MonoClass*
2356 mono_get_string_class (void)
2358 return mono_defaults.string_class;
2361 MonoClass*
2362 mono_get_enum_class (void)
2364 return mono_defaults.enum_class;
2367 MonoClass*
2368 mono_get_array_class (void)
2370 return mono_defaults.array_class;
2373 MonoClass*
2374 mono_get_thread_class (void)
2376 return mono_defaults.thread_class;
2379 MonoClass*
2380 mono_get_exception_class (void)
2382 return mono_defaults.exception_class;
2386 static char* get_attribute_value (const gchar **attribute_names,
2387 const gchar **attribute_values,
2388 const char *att_name)
2390 int n;
2391 for (n=0; attribute_names[n] != NULL; n++) {
2392 if (strcmp (attribute_names[n], att_name) == 0)
2393 return g_strdup (attribute_values[n]);
2395 return NULL;
2398 static void start_element (GMarkupParseContext *context,
2399 const gchar *element_name,
2400 const gchar **attribute_names,
2401 const gchar **attribute_values,
2402 gpointer user_data,
2403 GError **error)
2405 AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2407 if (strcmp (element_name, "configuration") == 0) {
2408 app_config->configuration_count++;
2409 return;
2411 if (strcmp (element_name, "startup") == 0) {
2412 app_config->startup_count++;
2413 return;
2416 if (app_config->configuration_count != 1 || app_config->startup_count != 1)
2417 return;
2419 if (strcmp (element_name, "requiredRuntime") == 0) {
2420 app_config->required_runtime = get_attribute_value (attribute_names, attribute_values, "version");
2421 } else if (strcmp (element_name, "supportedRuntime") == 0) {
2422 char *version = get_attribute_value (attribute_names, attribute_values, "version");
2423 app_config->supported_runtimes = g_slist_append (app_config->supported_runtimes, version);
2427 static void end_element (GMarkupParseContext *context,
2428 const gchar *element_name,
2429 gpointer user_data,
2430 GError **error)
2432 AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2434 if (strcmp (element_name, "configuration") == 0) {
2435 app_config->configuration_count--;
2436 } else if (strcmp (element_name, "startup") == 0) {
2437 app_config->startup_count--;
2441 static const GMarkupParser
2442 mono_parser = {
2443 start_element,
2444 end_element,
2445 NULL,
2446 NULL,
2447 NULL
2450 static AppConfigInfo *
2451 app_config_parse (const char *exe_filename)
2453 AppConfigInfo *app_config;
2454 GMarkupParseContext *context;
2455 char *text;
2456 gsize len;
2457 const char *bundled_config;
2458 char *config_filename;
2460 bundled_config = mono_config_string_for_assembly_file (exe_filename);
2462 if (bundled_config) {
2463 text = g_strdup (bundled_config);
2464 len = strlen (text);
2465 } else {
2466 config_filename = g_strconcat (exe_filename, ".config", NULL);
2468 if (!g_file_get_contents (config_filename, &text, &len, NULL)) {
2469 g_free (config_filename);
2470 return NULL;
2472 g_free (config_filename);
2475 app_config = g_new0 (AppConfigInfo, 1);
2477 context = g_markup_parse_context_new (&mono_parser, 0, app_config, NULL);
2478 if (g_markup_parse_context_parse (context, text, len, NULL)) {
2479 g_markup_parse_context_end_parse (context, NULL);
2481 g_markup_parse_context_free (context);
2482 g_free (text);
2483 return app_config;
2486 static void
2487 app_config_free (AppConfigInfo* app_config)
2489 char *rt;
2490 GSList *list = app_config->supported_runtimes;
2491 while (list != NULL) {
2492 rt = (char*)list->data;
2493 g_free (rt);
2494 list = g_slist_next (list);
2496 g_slist_free (app_config->supported_runtimes);
2497 g_free (app_config->required_runtime);
2498 g_free (app_config);
2502 static const MonoRuntimeInfo*
2503 get_runtime_by_version (const char *version)
2505 int n;
2506 int max = G_N_ELEMENTS (supported_runtimes);
2508 for (n=0; n<max; n++) {
2509 if (strcmp (version, supported_runtimes[n].runtime_version) == 0)
2510 return &supported_runtimes[n];
2512 return NULL;
2515 static void
2516 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes)
2518 AppConfigInfo* app_config;
2519 char *version;
2520 const MonoRuntimeInfo* runtime = NULL;
2521 MonoImage *image = NULL;
2523 app_config = app_config_parse (exe_file);
2525 if (app_config != NULL) {
2526 /* Check supportedRuntime elements, if none is supported, fail.
2527 * If there are no such elements, look for a requiredRuntime element.
2529 if (app_config->supported_runtimes != NULL) {
2530 int n = 0;
2531 GSList *list = app_config->supported_runtimes;
2532 while (list != NULL) {
2533 version = (char*) list->data;
2534 runtime = get_runtime_by_version (version);
2535 if (runtime != NULL)
2536 runtimes [n++] = runtime;
2537 list = g_slist_next (list);
2539 runtimes [n] = NULL;
2540 app_config_free (app_config);
2541 return;
2544 /* Check the requiredRuntime element. This is for 1.0 apps only. */
2545 if (app_config->required_runtime != NULL) {
2546 runtimes [0] = get_runtime_by_version (app_config->required_runtime);
2547 runtimes [1] = NULL;
2548 app_config_free (app_config);
2549 return;
2551 app_config_free (app_config);
2554 /* Look for a runtime with the exact version */
2555 image = mono_assembly_open_from_bundle (exe_file, NULL, FALSE);
2557 if (image == NULL)
2558 image = mono_image_open (exe_file, NULL);
2560 if (image == NULL) {
2561 /* The image is wrong or the file was not found. In this case return
2562 * a default runtime and leave to the initialization method the work of
2563 * reporting the error.
2565 runtimes [0] = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
2566 runtimes [1] = NULL;
2567 return;
2570 *exe_image = image;
2572 runtimes [0] = get_runtime_by_version (image->version);
2573 runtimes [1] = NULL;
2578 * mono_get_runtime_info:
2580 * Returns: the version of the current runtime instance.
2582 const MonoRuntimeInfo*
2583 mono_get_runtime_info (void)
2585 return current_runtime;
2588 gchar *
2589 mono_debugger_check_runtime_version (const char *filename)
2591 const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
2592 const MonoRuntimeInfo *rinfo;
2593 MonoImage *image;
2595 get_runtimes_from_exe (filename, &image, runtimes);
2596 rinfo = runtimes [0];
2598 if (!rinfo)
2599 return g_strdup_printf ("Cannot get runtime version from assembly `%s'", filename);
2601 if (rinfo != current_runtime)
2602 return g_strdup_printf ("The Mono Debugger is currently using the `%s' runtime, but "
2603 "the assembly `%s' requires version `%s'", current_runtime->runtime_version,
2604 filename, rinfo->runtime_version);
2606 return NULL;
2610 * mono_framework_version:
2612 * Return the major version of the framework curently executing.
2615 mono_framework_version (void)
2617 return current_runtime->framework_version [0] - '0';