[sgen] One internal allocator per worker thread, to get rid of locking.
[mono-project/dkf.git] / mono / metadata / domain.c
blobe161c325f1c8eb48a6be66d59f5f27dcc9116b1d
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}, { 3, 5, 0, 0 } } },
132 {"v2.0.50727","2.0", { {2,0,0,0}, {8,0,0,0}, { 3, 5, 0, 0 } } },
133 {"v4.0.30128","4.0", { {4,0,0,0}, {10,0,0,0}, { 4, 0, 0, 0 } } },
134 {"v4.0.30319","4.0", { {4,0,0,0}, {10,0,0,0}, { 4, 0, 0, 0 } } },
135 {"moonlight", "2.1", { {2,0,5,0}, {9,0,0,0}, { 3, 5, 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 return appdomain_thread_id;
164 gint32
165 mono_domain_get_tls_offset (void)
167 int offset = -1;
168 MONO_THREAD_VAR_OFFSET (tls_appdomain, offset);
169 /* __asm ("jmp 1f; .section writetext, \"awx\"; 1: movl $tls_appdomain@ntpoff, %0; jmp 2f; .previous; 2:"
170 : "=r" (offset));*/
171 return offset;
174 #define JIT_INFO_TABLE_FILL_RATIO_NOM 3
175 #define JIT_INFO_TABLE_FILL_RATIO_DENOM 4
176 #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)
178 #define JIT_INFO_TABLE_LOW_WATERMARK(n) ((n) / 2)
179 #define JIT_INFO_TABLE_HIGH_WATERMARK(n) ((n) * 5 / 6)
181 #define JIT_INFO_TOMBSTONE_MARKER ((MonoMethod*)NULL)
182 #define IS_JIT_INFO_TOMBSTONE(ji) ((ji)->method == JIT_INFO_TOMBSTONE_MARKER)
184 #define JIT_INFO_TABLE_HAZARD_INDEX 0
185 #define JIT_INFO_HAZARD_INDEX 1
187 static int
188 jit_info_table_num_elements (MonoJitInfoTable *table)
190 int i;
191 int num_elements = 0;
193 for (i = 0; i < table->num_chunks; ++i) {
194 MonoJitInfoTableChunk *chunk = table->chunks [i];
195 int chunk_num_elements = chunk->num_elements;
196 int j;
198 for (j = 0; j < chunk_num_elements; ++j) {
199 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j]))
200 ++num_elements;
204 return num_elements;
207 static MonoJitInfoTableChunk*
208 jit_info_table_new_chunk (void)
210 MonoJitInfoTableChunk *chunk = g_new0 (MonoJitInfoTableChunk, 1);
211 chunk->refcount = 1;
213 return chunk;
216 static MonoJitInfoTable *
217 jit_info_table_new (MonoDomain *domain)
219 MonoJitInfoTable *table = g_malloc0 (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*));
221 table->domain = domain;
222 table->num_chunks = 1;
223 table->chunks [0] = jit_info_table_new_chunk ();
225 return table;
228 static void
229 jit_info_table_free (MonoJitInfoTable *table)
231 int i;
232 int num_chunks = table->num_chunks;
233 MonoDomain *domain = table->domain;
235 mono_domain_lock (domain);
237 table->domain->num_jit_info_tables--;
238 if (table->domain->num_jit_info_tables <= 1) {
239 GSList *list;
241 for (list = table->domain->jit_info_free_queue; list; list = list->next)
242 g_free (list->data);
244 g_slist_free (table->domain->jit_info_free_queue);
245 table->domain->jit_info_free_queue = NULL;
248 /* At this point we assume that there are no other threads
249 still accessing the table, so we don't have to worry about
250 hazardous pointers. */
252 for (i = 0; i < num_chunks; ++i) {
253 MonoJitInfoTableChunk *chunk = table->chunks [i];
254 int num_elements;
255 int j;
257 if (--chunk->refcount > 0)
258 continue;
260 num_elements = chunk->num_elements;
261 for (j = 0; j < num_elements; ++j) {
262 MonoJitInfo *ji = chunk->data [j];
264 if (IS_JIT_INFO_TOMBSTONE (ji))
265 g_free (ji);
268 g_free (chunk);
271 mono_domain_unlock (domain);
273 g_free (table);
276 /* Can be called with hp==NULL, in which case it acts as an ordinary
277 pointer fetch. It's used that way indirectly from
278 mono_jit_info_table_add(), which doesn't have to care about hazards
279 because it holds the respective domain lock. */
280 static gpointer
281 get_hazardous_pointer (gpointer volatile *pp, MonoThreadHazardPointers *hp, int hazard_index)
283 gpointer p;
285 for (;;) {
286 /* Get the pointer */
287 p = *pp;
288 /* If we don't have hazard pointers just return the
289 pointer. */
290 if (!hp)
291 return p;
292 /* Make it hazardous */
293 mono_hazard_pointer_set (hp, hazard_index, p);
294 /* Check that it's still the same. If not, try
295 again. */
296 if (*pp != p) {
297 mono_hazard_pointer_clear (hp, hazard_index);
298 continue;
300 break;
303 return p;
306 /* The jit_info_table is sorted in ascending order by the end
307 * addresses of the compiled methods. The reason why we have to do
308 * this is that once we introduce tombstones, it becomes possible for
309 * code ranges to overlap, and if we sort by code start and insert at
310 * the back of the table, we cannot guarantee that we won't overlook
311 * an entry.
313 * There are actually two possible ways to do the sorting and
314 * inserting which work with our lock-free mechanism:
316 * 1. Sort by start address and insert at the front. When looking for
317 * an entry, find the last one with a start address lower than the one
318 * you're looking for, then work your way to the front of the table.
320 * 2. Sort by end address and insert at the back. When looking for an
321 * entry, find the first one with an end address higher than the one
322 * you're looking for, then work your way to the end of the table.
324 * We chose the latter out of convenience.
326 static int
327 jit_info_table_index (MonoJitInfoTable *table, gint8 *addr)
329 int left = 0, right = table->num_chunks;
331 g_assert (left < right);
333 do {
334 int pos = (left + right) / 2;
335 MonoJitInfoTableChunk *chunk = table->chunks [pos];
337 if (addr < chunk->last_code_end)
338 right = pos;
339 else
340 left = pos + 1;
341 } while (left < right);
342 g_assert (left == right);
344 if (left >= table->num_chunks)
345 return table->num_chunks - 1;
346 return left;
349 static int
350 jit_info_table_chunk_index (MonoJitInfoTableChunk *chunk, MonoThreadHazardPointers *hp, gint8 *addr)
352 int left = 0, right = chunk->num_elements;
354 while (left < right) {
355 int pos = (left + right) / 2;
356 MonoJitInfo *ji = get_hazardous_pointer((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
357 gint8 *code_end = (gint8*)ji->code_start + ji->code_size;
359 if (addr < code_end)
360 right = pos;
361 else
362 left = pos + 1;
364 g_assert (left == right);
366 return left;
369 MonoJitInfo*
370 mono_jit_info_table_find (MonoDomain *domain, char *addr)
372 MonoJitInfoTable *table;
373 MonoJitInfo *ji;
374 int chunk_pos, pos;
375 MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
376 MonoImage *image;
378 ++mono_stats.jit_info_table_lookup_count;
380 /* First we have to get the domain's jit_info_table. This is
381 complicated by the fact that a writer might substitute a
382 new table and free the old one. What the writer guarantees
383 us is that it looks at the hazard pointers after it has
384 changed the jit_info_table pointer. So, if we guard the
385 table by a hazard pointer and make sure that the pointer is
386 still there after we've made it hazardous, we don't have to
387 worry about the writer freeing the table. */
388 table = get_hazardous_pointer ((gpointer volatile*)&domain->jit_info_table, hp, JIT_INFO_TABLE_HAZARD_INDEX);
390 chunk_pos = jit_info_table_index (table, (gint8*)addr);
391 g_assert (chunk_pos < table->num_chunks);
393 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], hp, (gint8*)addr);
395 /* We now have a position that's very close to that of the
396 first element whose end address is higher than the one
397 we're looking for. If we don't have the exact position,
398 then we have a position below that one, so we'll just
399 search upward until we find our element. */
400 do {
401 MonoJitInfoTableChunk *chunk = table->chunks [chunk_pos];
403 while (pos < chunk->num_elements) {
404 ji = get_hazardous_pointer ((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
406 ++pos;
408 if (IS_JIT_INFO_TOMBSTONE (ji)) {
409 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
410 continue;
412 if ((gint8*)addr >= (gint8*)ji->code_start
413 && (gint8*)addr < (gint8*)ji->code_start + ji->code_size) {
414 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
415 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
416 return ji;
419 /* If we find a non-tombstone element which is already
420 beyond what we're looking for, we have to end the
421 search. */
422 if ((gint8*)addr < (gint8*)ji->code_start)
423 goto not_found;
426 ++chunk_pos;
427 pos = 0;
428 } while (chunk_pos < table->num_chunks);
430 not_found:
431 if (!hp)
432 return NULL;
434 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
435 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
437 ji = NULL;
439 /* Maybe its an AOT module */
440 image = mono_jit_info_find_aot_module ((guint8*)addr);
441 if (image)
442 ji = jit_info_find_in_aot_func (domain, image, addr);
444 return ji;
447 static G_GNUC_UNUSED void
448 jit_info_table_check (MonoJitInfoTable *table)
450 int i;
452 for (i = 0; i < table->num_chunks; ++i) {
453 MonoJitInfoTableChunk *chunk = table->chunks [i];
454 int j;
456 g_assert (chunk->refcount > 0 /* && chunk->refcount <= 8 */);
457 if (chunk->refcount > 10)
458 printf("warning: chunk refcount is %d\n", chunk->refcount);
459 g_assert (chunk->num_elements <= MONO_JIT_INFO_TABLE_CHUNK_SIZE);
461 for (j = 0; j < chunk->num_elements; ++j) {
462 MonoJitInfo *this = chunk->data [j];
463 MonoJitInfo *next;
465 g_assert ((gint8*)this->code_start + this->code_size <= chunk->last_code_end);
467 if (j < chunk->num_elements - 1)
468 next = chunk->data [j + 1];
469 else if (i < table->num_chunks - 1) {
470 int k;
472 for (k = i + 1; k < table->num_chunks; ++k)
473 if (table->chunks [k]->num_elements > 0)
474 break;
476 if (k >= table->num_chunks)
477 return;
479 g_assert (table->chunks [k]->num_elements > 0);
480 next = table->chunks [k]->data [0];
481 } else
482 return;
484 g_assert ((gint8*)this->code_start + this->code_size <= (gint8*)next->code_start + next->code_size);
489 static MonoJitInfoTable*
490 jit_info_table_realloc (MonoJitInfoTable *old)
492 int i;
493 int num_elements = jit_info_table_num_elements (old);
494 int required_size;
495 int num_chunks;
496 int new_chunk, new_element;
497 MonoJitInfoTable *new;
499 /* number of needed places for elements needed */
500 required_size = (int)((long)num_elements * JIT_INFO_TABLE_FILL_RATIO_DENOM / JIT_INFO_TABLE_FILL_RATIO_NOM);
501 num_chunks = (required_size + MONO_JIT_INFO_TABLE_CHUNK_SIZE - 1) / MONO_JIT_INFO_TABLE_CHUNK_SIZE;
503 new = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*) * num_chunks);
504 new->domain = old->domain;
505 new->num_chunks = num_chunks;
507 for (i = 0; i < num_chunks; ++i)
508 new->chunks [i] = jit_info_table_new_chunk ();
510 new_chunk = 0;
511 new_element = 0;
512 for (i = 0; i < old->num_chunks; ++i) {
513 MonoJitInfoTableChunk *chunk = old->chunks [i];
514 int chunk_num_elements = chunk->num_elements;
515 int j;
517 for (j = 0; j < chunk_num_elements; ++j) {
518 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j])) {
519 g_assert (new_chunk < num_chunks);
520 new->chunks [new_chunk]->data [new_element] = chunk->data [j];
521 if (++new_element >= JIT_INFO_TABLE_FILLED_NUM_ELEMENTS) {
522 new->chunks [new_chunk]->num_elements = new_element;
523 ++new_chunk;
524 new_element = 0;
530 if (new_chunk < num_chunks) {
531 g_assert (new_chunk == num_chunks - 1);
532 new->chunks [new_chunk]->num_elements = new_element;
533 g_assert (new->chunks [new_chunk]->num_elements > 0);
536 for (i = 0; i < num_chunks; ++i) {
537 MonoJitInfoTableChunk *chunk = new->chunks [i];
538 MonoJitInfo *ji = chunk->data [chunk->num_elements - 1];
540 new->chunks [i]->last_code_end = (gint8*)ji->code_start + ji->code_size;
543 return new;
546 static void
547 jit_info_table_split_chunk (MonoJitInfoTableChunk *chunk, MonoJitInfoTableChunk **new1p, MonoJitInfoTableChunk **new2p)
549 MonoJitInfoTableChunk *new1 = jit_info_table_new_chunk ();
550 MonoJitInfoTableChunk *new2 = jit_info_table_new_chunk ();
552 g_assert (chunk->num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE);
554 new1->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE / 2;
555 new2->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE - new1->num_elements;
557 memcpy ((void*)new1->data, (void*)chunk->data, sizeof (MonoJitInfo*) * new1->num_elements);
558 memcpy ((void*)new2->data, (void*)(chunk->data + new1->num_elements), sizeof (MonoJitInfo*) * new2->num_elements);
560 new1->last_code_end = (gint8*)new1->data [new1->num_elements - 1]->code_start
561 + new1->data [new1->num_elements - 1]->code_size;
562 new2->last_code_end = (gint8*)new2->data [new2->num_elements - 1]->code_start
563 + new2->data [new2->num_elements - 1]->code_size;
565 *new1p = new1;
566 *new2p = new2;
569 static MonoJitInfoTable*
570 jit_info_table_copy_and_split_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
572 MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
573 + sizeof (MonoJitInfoTableChunk*) * (table->num_chunks + 1));
574 int i, j;
576 new_table->domain = table->domain;
577 new_table->num_chunks = table->num_chunks + 1;
579 j = 0;
580 for (i = 0; i < table->num_chunks; ++i) {
581 if (table->chunks [i] == chunk) {
582 jit_info_table_split_chunk (chunk, &new_table->chunks [j], &new_table->chunks [j + 1]);
583 j += 2;
584 } else {
585 new_table->chunks [j] = table->chunks [i];
586 ++new_table->chunks [j]->refcount;
587 ++j;
591 g_assert (j == new_table->num_chunks);
593 return new_table;
596 static MonoJitInfoTableChunk*
597 jit_info_table_purify_chunk (MonoJitInfoTableChunk *old)
599 MonoJitInfoTableChunk *new = jit_info_table_new_chunk ();
600 int i, j;
602 j = 0;
603 for (i = 0; i < old->num_elements; ++i) {
604 if (!IS_JIT_INFO_TOMBSTONE (old->data [i]))
605 new->data [j++] = old->data [i];
608 new->num_elements = j;
609 if (new->num_elements > 0)
610 new->last_code_end = (gint8*)new->data [j - 1]->code_start + new->data [j - 1]->code_size;
611 else
612 new->last_code_end = old->last_code_end;
614 return new;
617 static MonoJitInfoTable*
618 jit_info_table_copy_and_purify_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
620 MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
621 + sizeof (MonoJitInfoTableChunk*) * table->num_chunks);
622 int i, j;
624 new_table->domain = table->domain;
625 new_table->num_chunks = table->num_chunks;
627 j = 0;
628 for (i = 0; i < table->num_chunks; ++i) {
629 if (table->chunks [i] == chunk)
630 new_table->chunks [j++] = jit_info_table_purify_chunk (table->chunks [i]);
631 else {
632 new_table->chunks [j] = table->chunks [i];
633 ++new_table->chunks [j]->refcount;
634 ++j;
638 g_assert (j == new_table->num_chunks);
640 return new_table;
643 /* As we add an element to the table the case can arise that the chunk
644 * to which we need to add is already full. In that case we have to
645 * allocate a new table and do something about that chunk. We have
646 * several strategies:
648 * If the number of elements in the table is below the low watermark
649 * or above the high watermark, we reallocate the whole table.
650 * Otherwise we only concern ourselves with the overflowing chunk:
652 * If there are no tombstones in the chunk then we split the chunk in
653 * two, each half full.
655 * If the chunk does contain tombstones, we just make a new copy of
656 * the chunk without the tombstones, which will have room for at least
657 * the one element we have to add.
659 static MonoJitInfoTable*
660 jit_info_table_chunk_overflow (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
662 int num_elements = jit_info_table_num_elements (table);
663 int i;
665 if (num_elements < JIT_INFO_TABLE_LOW_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)
666 || num_elements > JIT_INFO_TABLE_HIGH_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)) {
667 //printf ("reallocing table\n");
668 return jit_info_table_realloc (table);
671 /* count the number of non-tombstone elements in the chunk */
672 num_elements = 0;
673 for (i = 0; i < chunk->num_elements; ++i) {
674 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [i]))
675 ++num_elements;
678 if (num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
679 //printf ("splitting chunk\n");
680 return jit_info_table_copy_and_split_chunk (table, chunk);
683 //printf ("purifying chunk\n");
684 return jit_info_table_copy_and_purify_chunk (table, chunk);
687 /* We add elements to the table by first making space for them by
688 * shifting the elements at the back to the right, one at a time.
689 * This results in duplicate entries during the process, but during
690 * all the time the table is in a sorted state. Also, when an element
691 * is replaced by another one, the element that replaces it has an end
692 * address that is equal to or lower than that of the replaced
693 * element. That property is necessary to guarantee that when
694 * searching for an element we end up at a position not higher than
695 * the one we're looking for (i.e. we either find the element directly
696 * or we end up to the left of it).
698 void
699 mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
701 MonoJitInfoTable *table;
702 int chunk_pos, pos;
703 MonoJitInfoTableChunk *chunk;
704 int num_elements;
705 int i;
707 g_assert (ji->method != NULL);
709 mono_domain_lock (domain);
711 ++mono_stats.jit_info_table_insert_count;
713 table = domain->jit_info_table;
715 restart:
716 chunk_pos = jit_info_table_index (table, (gint8*)ji->code_start + ji->code_size);
717 g_assert (chunk_pos < table->num_chunks);
718 chunk = table->chunks [chunk_pos];
720 if (chunk->num_elements >= MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
721 MonoJitInfoTable *new_table = jit_info_table_chunk_overflow (table, chunk);
723 /* Debugging code, should be removed. */
724 //jit_info_table_check (new_table);
726 domain->jit_info_table = new_table;
727 mono_memory_barrier ();
728 domain->num_jit_info_tables++;
729 mono_thread_hazardous_free_or_queue (table, (MonoHazardousFreeFunc)jit_info_table_free);
730 table = new_table;
732 goto restart;
735 /* Debugging code, should be removed. */
736 //jit_info_table_check (table);
738 num_elements = chunk->num_elements;
740 pos = jit_info_table_chunk_index (chunk, NULL, (gint8*)ji->code_start + ji->code_size);
742 /* First we need to size up the chunk by one, by copying the
743 last item, or inserting the first one, if the table is
744 empty. */
745 if (num_elements > 0)
746 chunk->data [num_elements] = chunk->data [num_elements - 1];
747 else
748 chunk->data [0] = ji;
749 mono_memory_write_barrier ();
750 chunk->num_elements = ++num_elements;
752 /* Shift the elements up one by one. */
753 for (i = num_elements - 2; i >= pos; --i) {
754 mono_memory_write_barrier ();
755 chunk->data [i + 1] = chunk->data [i];
758 /* Now we have room and can insert the new item. */
759 mono_memory_write_barrier ();
760 chunk->data [pos] = ji;
762 /* Set the high code end address chunk entry. */
763 chunk->last_code_end = (gint8*)chunk->data [chunk->num_elements - 1]->code_start
764 + chunk->data [chunk->num_elements - 1]->code_size;
766 /* Debugging code, should be removed. */
767 //jit_info_table_check (table);
769 mono_domain_unlock (domain);
772 static MonoJitInfo*
773 mono_jit_info_make_tombstone (MonoJitInfo *ji)
775 MonoJitInfo *tombstone = g_new0 (MonoJitInfo, 1);
777 tombstone->code_start = ji->code_start;
778 tombstone->code_size = ji->code_size;
779 tombstone->method = JIT_INFO_TOMBSTONE_MARKER;
781 return tombstone;
785 * LOCKING: domain lock
787 static void
788 mono_jit_info_free_or_queue (MonoDomain *domain, MonoJitInfo *ji)
790 if (domain->num_jit_info_tables <= 1) {
791 /* Can it actually happen that we only have one table
792 but ji is still hazardous? */
793 mono_thread_hazardous_free_or_queue (ji, g_free);
794 } else {
795 domain->jit_info_free_queue = g_slist_prepend (domain->jit_info_free_queue, ji);
799 void
800 mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
802 MonoJitInfoTable *table;
803 MonoJitInfoTableChunk *chunk;
804 gpointer start = ji->code_start;
805 int chunk_pos, pos;
807 mono_domain_lock (domain);
808 table = domain->jit_info_table;
810 ++mono_stats.jit_info_table_remove_count;
812 chunk_pos = jit_info_table_index (table, start);
813 g_assert (chunk_pos < table->num_chunks);
815 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], NULL, start);
817 do {
818 chunk = table->chunks [chunk_pos];
820 while (pos < chunk->num_elements) {
821 if (chunk->data [pos] == ji)
822 goto found;
824 g_assert (IS_JIT_INFO_TOMBSTONE (chunk->data [pos]));
825 g_assert ((guint8*)chunk->data [pos]->code_start + chunk->data [pos]->code_size
826 <= (guint8*)ji->code_start + ji->code_size);
828 ++pos;
831 ++chunk_pos;
832 pos = 0;
833 } while (chunk_pos < table->num_chunks);
835 found:
836 g_assert (chunk->data [pos] == ji);
838 chunk->data [pos] = mono_jit_info_make_tombstone (ji);
840 /* Debugging code, should be removed. */
841 //jit_info_table_check (table);
843 mono_jit_info_free_or_queue (domain, ji);
845 mono_domain_unlock (domain);
848 static MonoAotModuleInfoTable*
849 mono_aot_module_info_table_new (void)
851 return g_array_new (FALSE, FALSE, sizeof (gpointer));
854 static int
855 aot_info_table_index (MonoAotModuleInfoTable *table, char *addr)
857 int left = 0, right = table->len;
859 while (left < right) {
860 int pos = (left + right) / 2;
861 AotModuleInfo *ainfo = g_array_index (table, gpointer, pos);
862 char *start = ainfo->start;
863 char *end = ainfo->end;
865 if (addr < start)
866 right = pos;
867 else if (addr >= end)
868 left = pos + 1;
869 else
870 return pos;
873 return left;
876 void
877 mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
879 AotModuleInfo *ainfo = g_new0 (AotModuleInfo, 1);
880 int pos;
882 ainfo->image = image;
883 ainfo->start = start;
884 ainfo->end = end;
886 mono_appdomains_lock ();
888 if (!aot_modules)
889 aot_modules = mono_aot_module_info_table_new ();
891 pos = aot_info_table_index (aot_modules, start);
893 g_array_insert_val (aot_modules, pos, ainfo);
895 mono_appdomains_unlock ();
898 static MonoImage*
899 mono_jit_info_find_aot_module (guint8* addr)
901 guint left = 0, right;
903 if (!aot_modules)
904 return NULL;
906 mono_appdomains_lock ();
908 right = aot_modules->len;
909 while (left < right) {
910 guint pos = (left + right) / 2;
911 AotModuleInfo *ai = g_array_index (aot_modules, gpointer, pos);
913 if (addr < (guint8*)ai->start)
914 right = pos;
915 else if (addr >= (guint8*)ai->end)
916 left = pos + 1;
917 else {
918 mono_appdomains_unlock ();
919 return ai->image;
923 mono_appdomains_unlock ();
925 return NULL;
928 void
929 mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func)
931 jit_info_find_in_aot_func = func;
934 gpointer
935 mono_jit_info_get_code_start (MonoJitInfo* ji)
937 return ji->code_start;
941 mono_jit_info_get_code_size (MonoJitInfo* ji)
943 return ji->code_size;
946 MonoMethod*
947 mono_jit_info_get_method (MonoJitInfo* ji)
949 return ji->method;
952 static gpointer
953 jit_info_key_extract (gpointer value)
955 MonoJitInfo *info = (MonoJitInfo*)value;
957 return info->method;
960 static gpointer*
961 jit_info_next_value (gpointer value)
963 MonoJitInfo *info = (MonoJitInfo*)value;
965 return (gpointer*)&info->next_jit_code_hash;
968 void
969 mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
971 mono_internal_hash_table_init (jit_code_hash,
972 mono_aligned_addr_hash,
973 jit_info_key_extract,
974 jit_info_next_value);
977 MonoGenericJitInfo*
978 mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
980 if (ji->has_generic_jit_info)
981 return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
982 else
983 return NULL;
987 * mono_jit_info_get_generic_sharing_context:
988 * @ji: a jit info
990 * Returns the jit info's generic sharing context, or NULL if it
991 * doesn't have one.
993 MonoGenericSharingContext*
994 mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
996 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
998 if (gi)
999 return gi->generic_sharing_context;
1000 else
1001 return NULL;
1005 * mono_jit_info_set_generic_sharing_context:
1006 * @ji: a jit info
1007 * @gsctx: a generic sharing context
1009 * Sets the jit info's generic sharing context. The jit info must
1010 * have memory allocated for the context.
1012 void
1013 mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
1015 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
1017 g_assert (gi);
1019 gi->generic_sharing_context = gsctx;
1022 MonoTryBlockHoleTableJitInfo*
1023 mono_jit_info_get_try_block_hole_table_info (MonoJitInfo *ji)
1025 if (ji->has_try_block_holes) {
1026 char *ptr = (char*)&ji->clauses [ji->num_clauses];
1027 if (ji->has_generic_jit_info)
1028 ptr += sizeof (MonoGenericJitInfo);
1029 return (MonoTryBlockHoleTableJitInfo*)ptr;
1030 } else {
1031 return NULL;
1034 void
1035 mono_install_create_domain_hook (MonoCreateDomainFunc func)
1037 create_domain_hook = func;
1040 void
1041 mono_install_free_domain_hook (MonoFreeDomainFunc func)
1043 free_domain_hook = func;
1047 * mono_string_equal:
1048 * @s1: First string to compare
1049 * @s2: Second string to compare
1051 * Returns FALSE if the strings differ.
1053 gboolean
1054 mono_string_equal (MonoString *s1, MonoString *s2)
1056 int l1 = mono_string_length (s1);
1057 int l2 = mono_string_length (s2);
1059 if (s1 == s2)
1060 return TRUE;
1061 if (l1 != l2)
1062 return FALSE;
1064 return memcmp (mono_string_chars (s1), mono_string_chars (s2), l1 * 2) == 0;
1068 * mono_string_hash:
1069 * @s: the string to hash
1071 * Returns the hash for the string.
1073 guint
1074 mono_string_hash (MonoString *s)
1076 const guint16 *p = mono_string_chars (s);
1077 int i, len = mono_string_length (s);
1078 guint h = 0;
1080 for (i = 0; i < len; i++) {
1081 h = (h << 5) - h + *p;
1082 p++;
1085 return h;
1088 static gboolean
1089 mono_ptrarray_equal (gpointer *s1, gpointer *s2)
1091 int len = GPOINTER_TO_INT (s1 [0]);
1092 if (len != GPOINTER_TO_INT (s2 [0]))
1093 return FALSE;
1095 return memcmp (s1 + 1, s2 + 1, len * sizeof(gpointer)) == 0;
1098 static guint
1099 mono_ptrarray_hash (gpointer *s)
1101 int i;
1102 int len = GPOINTER_TO_INT (s [0]);
1103 guint hash = 0;
1105 for (i = 1; i < len; i++)
1106 hash += GPOINTER_TO_UINT (s [i]);
1108 return hash;
1112 * Allocate an id for domain and set domain->domain_id.
1113 * LOCKING: must be called while holding appdomains_mutex.
1114 * We try to assign low numbers to the domain, so it can be used
1115 * as an index in data tables to lookup domain-specific info
1116 * with minimal memory overhead. We also try not to reuse the
1117 * same id too quickly (to help debugging).
1119 static int
1120 domain_id_alloc (MonoDomain *domain)
1122 int id = -1, i;
1123 if (!appdomains_list) {
1124 appdomain_list_size = 2;
1125 appdomains_list = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1127 for (i = appdomain_next; i < appdomain_list_size; ++i) {
1128 if (!appdomains_list [i]) {
1129 id = i;
1130 break;
1133 if (id == -1) {
1134 for (i = 0; i < appdomain_next; ++i) {
1135 if (!appdomains_list [i]) {
1136 id = i;
1137 break;
1141 if (id == -1) {
1142 MonoDomain **new_list;
1143 int new_size = appdomain_list_size * 2;
1144 if (new_size >= (1 << 16))
1145 g_assert_not_reached ();
1146 id = appdomain_list_size;
1147 new_list = mono_gc_alloc_fixed (new_size * sizeof (void*), NULL);
1148 memcpy (new_list, appdomains_list, appdomain_list_size * sizeof (void*));
1149 mono_gc_free_fixed (appdomains_list);
1150 appdomains_list = new_list;
1151 appdomain_list_size = new_size;
1153 domain->domain_id = id;
1154 appdomains_list [id] = domain;
1155 appdomain_next++;
1156 if (appdomain_next > appdomain_list_size)
1157 appdomain_next = 0;
1158 return id;
1161 static gsize domain_gc_bitmap [sizeof(MonoDomain)/4/32 + 1];
1162 static gpointer domain_gc_desc = NULL;
1163 static guint32 domain_shadow_serial = 0L;
1165 MonoDomain *
1166 mono_domain_create (void)
1168 MonoDomain *domain;
1169 guint32 shadow_serial;
1171 mono_appdomains_lock ();
1172 shadow_serial = domain_shadow_serial++;
1174 if (!domain_gc_desc) {
1175 unsigned int i, bit = 0;
1176 for (i = G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_OBJECT); i < G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_GC_TRACKED); i += sizeof (gpointer)) {
1177 bit = i / sizeof (gpointer);
1178 domain_gc_bitmap [bit / 32] |= (gsize) 1 << (bit % 32);
1180 domain_gc_desc = mono_gc_make_descr_from_bitmap ((gsize*)domain_gc_bitmap, bit + 1);
1182 mono_appdomains_unlock ();
1184 domain = mono_gc_alloc_fixed (sizeof (MonoDomain), domain_gc_desc);
1185 domain->shadow_serial = shadow_serial;
1186 domain->domain = NULL;
1187 domain->setup = NULL;
1188 domain->friendly_name = NULL;
1189 domain->search_path = NULL;
1191 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);
1193 mono_profiler_appdomain_event (domain, MONO_PROFILE_START_LOAD);
1195 domain->mp = mono_mempool_new ();
1196 domain->code_mp = mono_code_manager_new ();
1197 domain->env = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1198 domain->domain_assemblies = NULL;
1199 domain->assembly_bindings = NULL;
1200 domain->assembly_bindings_parsed = FALSE;
1201 domain->class_vtable_array = g_ptr_array_new ();
1202 domain->proxy_vtable_hash = g_hash_table_new ((GHashFunc)mono_ptrarray_hash, (GCompareFunc)mono_ptrarray_equal);
1203 domain->static_data_array = NULL;
1204 mono_jit_code_hash_init (&domain->jit_code_hash);
1205 domain->ldstr_table = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1206 domain->num_jit_info_tables = 1;
1207 domain->jit_info_table = jit_info_table_new (domain);
1208 domain->jit_info_free_queue = NULL;
1209 domain->finalizable_objects_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1210 #ifndef HAVE_SGEN_GC
1211 domain->track_resurrection_handles_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1212 #endif
1214 InitializeCriticalSection (&domain->lock);
1215 InitializeCriticalSection (&domain->assemblies_lock);
1216 InitializeCriticalSection (&domain->jit_code_hash_lock);
1217 InitializeCriticalSection (&domain->finalizable_objects_hash_lock);
1219 domain->method_rgctx_hash = NULL;
1221 mono_appdomains_lock ();
1222 domain_id_alloc (domain);
1223 mono_appdomains_unlock ();
1225 mono_perfcounters->loader_appdomains++;
1226 mono_perfcounters->loader_total_appdomains++;
1228 mono_debug_domain_create (domain);
1230 if (create_domain_hook)
1231 create_domain_hook (domain);
1233 mono_profiler_appdomain_loaded (domain, MONO_PROFILE_OK);
1235 return domain;
1239 * mono_init_internal:
1241 * Creates the initial application domain and initializes the mono_defaults
1242 * structure.
1243 * This function is guaranteed to not run any IL code.
1244 * If exe_filename is not NULL, the method will determine the required runtime
1245 * from the exe configuration file or the version PE field.
1246 * If runtime_version is not NULL, that runtime version will be used.
1247 * Either exe_filename or runtime_version must be provided.
1249 * Returns: the initial domain.
1251 static MonoDomain *
1252 mono_init_internal (const char *filename, const char *exe_filename, const char *runtime_version)
1254 static MonoDomain *domain = NULL;
1255 MonoAssembly *ass = NULL;
1256 MonoImageOpenStatus status = MONO_IMAGE_OK;
1257 const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
1258 int n;
1260 if (domain)
1261 g_assert_not_reached ();
1263 #ifdef HOST_WIN32
1264 /* Avoid system error message boxes. */
1265 SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1267 mono_load_coree (exe_filename);
1268 #endif
1270 mono_perfcounters_init ();
1272 mono_counters_register ("Max native code in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_size);
1273 mono_counters_register ("Max code space allocated in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_alloc);
1274 mono_counters_register ("Total code space allocated", MONO_COUNTER_INT|MONO_COUNTER_JIT, &total_domain_code_alloc);
1276 mono_gc_base_init ();
1278 appdomain_thread_id = TlsAlloc ();
1280 InitializeCriticalSection (&appdomains_mutex);
1282 mono_metadata_init ();
1283 mono_images_init ();
1284 mono_assemblies_init ();
1285 mono_classes_init ();
1286 mono_loader_init ();
1287 mono_reflection_init ();
1289 /* FIXME: When should we release this memory? */
1290 MONO_GC_REGISTER_ROOT (appdomains_list);
1292 domain = mono_domain_create ();
1293 mono_root_domain = domain;
1295 SET_APPDOMAIN (domain);
1297 /* Get a list of runtimes supported by the exe */
1298 if (exe_filename != NULL) {
1300 * This function will load the exe file as a MonoImage. We need to close it, but
1301 * that would mean it would be reloaded later. So instead, we save it to
1302 * exe_image, and close it during shutdown.
1304 get_runtimes_from_exe (exe_filename, &exe_image, runtimes);
1305 #ifdef HOST_WIN32
1306 if (!exe_image) {
1307 exe_image = mono_assembly_open_from_bundle (exe_filename, NULL, FALSE);
1308 if (!exe_image)
1309 exe_image = mono_image_open (exe_filename, NULL);
1311 mono_fixup_exe_image (exe_image);
1312 #endif
1313 } else if (runtime_version != NULL) {
1314 runtimes [0] = get_runtime_by_version (runtime_version);
1315 runtimes [1] = NULL;
1318 if (runtimes [0] == NULL) {
1319 const MonoRuntimeInfo *default_runtime = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
1320 runtimes [0] = default_runtime;
1321 runtimes [1] = NULL;
1322 g_print ("WARNING: The runtime version supported by this application is unavailable.\n");
1323 g_print ("Using default runtime: %s\n", default_runtime->runtime_version);
1326 /* The selected runtime will be the first one for which there is a mscrolib.dll */
1327 for (n = 0; runtimes [n] != NULL && ass == NULL; n++) {
1328 current_runtime = runtimes [n];
1329 ass = mono_assembly_load_corlib (current_runtime, &status);
1330 if (status != MONO_IMAGE_OK && status != MONO_IMAGE_ERROR_ERRNO)
1331 break;
1335 if ((status != MONO_IMAGE_OK) || (ass == NULL)) {
1336 switch (status){
1337 case MONO_IMAGE_ERROR_ERRNO: {
1338 char *corlib_file = g_build_filename (mono_assembly_getrootdir (), "mono", current_runtime->framework_version, "mscorlib.dll", NULL);
1339 g_print ("The assembly mscorlib.dll was not found or could not be loaded.\n");
1340 g_print ("It should have been installed in the `%s' directory.\n", corlib_file);
1341 g_free (corlib_file);
1342 break;
1344 case MONO_IMAGE_IMAGE_INVALID:
1345 g_print ("The file %s/mscorlib.dll is an invalid CIL image\n",
1346 mono_assembly_getrootdir ());
1347 break;
1348 case MONO_IMAGE_MISSING_ASSEMBLYREF:
1349 g_print ("Missing assembly reference in %s/mscorlib.dll\n",
1350 mono_assembly_getrootdir ());
1351 break;
1352 case MONO_IMAGE_OK:
1353 /* to suppress compiler warning */
1354 break;
1357 exit (1);
1359 mono_defaults.corlib = mono_assembly_get_image (ass);
1361 mono_defaults.object_class = mono_class_from_name (
1362 mono_defaults.corlib, "System", "Object");
1363 g_assert (mono_defaults.object_class != 0);
1365 mono_defaults.void_class = mono_class_from_name (
1366 mono_defaults.corlib, "System", "Void");
1367 g_assert (mono_defaults.void_class != 0);
1369 mono_defaults.boolean_class = mono_class_from_name (
1370 mono_defaults.corlib, "System", "Boolean");
1371 g_assert (mono_defaults.boolean_class != 0);
1373 mono_defaults.byte_class = mono_class_from_name (
1374 mono_defaults.corlib, "System", "Byte");
1375 g_assert (mono_defaults.byte_class != 0);
1377 mono_defaults.sbyte_class = mono_class_from_name (
1378 mono_defaults.corlib, "System", "SByte");
1379 g_assert (mono_defaults.sbyte_class != 0);
1381 mono_defaults.int16_class = mono_class_from_name (
1382 mono_defaults.corlib, "System", "Int16");
1383 g_assert (mono_defaults.int16_class != 0);
1385 mono_defaults.uint16_class = mono_class_from_name (
1386 mono_defaults.corlib, "System", "UInt16");
1387 g_assert (mono_defaults.uint16_class != 0);
1389 mono_defaults.int32_class = mono_class_from_name (
1390 mono_defaults.corlib, "System", "Int32");
1391 g_assert (mono_defaults.int32_class != 0);
1393 mono_defaults.uint32_class = mono_class_from_name (
1394 mono_defaults.corlib, "System", "UInt32");
1395 g_assert (mono_defaults.uint32_class != 0);
1397 mono_defaults.uint_class = mono_class_from_name (
1398 mono_defaults.corlib, "System", "UIntPtr");
1399 g_assert (mono_defaults.uint_class != 0);
1401 mono_defaults.int_class = mono_class_from_name (
1402 mono_defaults.corlib, "System", "IntPtr");
1403 g_assert (mono_defaults.int_class != 0);
1405 mono_defaults.int64_class = mono_class_from_name (
1406 mono_defaults.corlib, "System", "Int64");
1407 g_assert (mono_defaults.int64_class != 0);
1409 mono_defaults.uint64_class = mono_class_from_name (
1410 mono_defaults.corlib, "System", "UInt64");
1411 g_assert (mono_defaults.uint64_class != 0);
1413 mono_defaults.single_class = mono_class_from_name (
1414 mono_defaults.corlib, "System", "Single");
1415 g_assert (mono_defaults.single_class != 0);
1417 mono_defaults.double_class = mono_class_from_name (
1418 mono_defaults.corlib, "System", "Double");
1419 g_assert (mono_defaults.double_class != 0);
1421 mono_defaults.char_class = mono_class_from_name (
1422 mono_defaults.corlib, "System", "Char");
1423 g_assert (mono_defaults.char_class != 0);
1425 mono_defaults.string_class = mono_class_from_name (
1426 mono_defaults.corlib, "System", "String");
1427 g_assert (mono_defaults.string_class != 0);
1429 mono_defaults.enum_class = mono_class_from_name (
1430 mono_defaults.corlib, "System", "Enum");
1431 g_assert (mono_defaults.enum_class != 0);
1433 mono_defaults.array_class = mono_class_from_name (
1434 mono_defaults.corlib, "System", "Array");
1435 g_assert (mono_defaults.array_class != 0);
1437 mono_defaults.delegate_class = mono_class_from_name (
1438 mono_defaults.corlib, "System", "Delegate");
1439 g_assert (mono_defaults.delegate_class != 0 );
1441 mono_defaults.multicastdelegate_class = mono_class_from_name (
1442 mono_defaults.corlib, "System", "MulticastDelegate");
1443 g_assert (mono_defaults.multicastdelegate_class != 0 );
1445 mono_defaults.asyncresult_class = mono_class_from_name (
1446 mono_defaults.corlib, "System.Runtime.Remoting.Messaging",
1447 "AsyncResult");
1448 g_assert (mono_defaults.asyncresult_class != 0 );
1450 mono_defaults.manualresetevent_class = mono_class_from_name (
1451 mono_defaults.corlib, "System.Threading", "ManualResetEvent");
1452 g_assert (mono_defaults.manualresetevent_class != 0 );
1454 mono_defaults.typehandle_class = mono_class_from_name (
1455 mono_defaults.corlib, "System", "RuntimeTypeHandle");
1456 g_assert (mono_defaults.typehandle_class != 0);
1458 mono_defaults.methodhandle_class = mono_class_from_name (
1459 mono_defaults.corlib, "System", "RuntimeMethodHandle");
1460 g_assert (mono_defaults.methodhandle_class != 0);
1462 mono_defaults.fieldhandle_class = mono_class_from_name (
1463 mono_defaults.corlib, "System", "RuntimeFieldHandle");
1464 g_assert (mono_defaults.fieldhandle_class != 0);
1466 mono_defaults.systemtype_class = mono_class_from_name (
1467 mono_defaults.corlib, "System", "Type");
1468 g_assert (mono_defaults.systemtype_class != 0);
1470 mono_defaults.monotype_class = mono_class_from_name (
1471 mono_defaults.corlib, "System", "MonoType");
1472 g_assert (mono_defaults.monotype_class != 0);
1474 mono_defaults.exception_class = mono_class_from_name (
1475 mono_defaults.corlib, "System", "Exception");
1476 g_assert (mono_defaults.exception_class != 0);
1478 mono_defaults.threadabortexception_class = mono_class_from_name (
1479 mono_defaults.corlib, "System.Threading", "ThreadAbortException");
1480 g_assert (mono_defaults.threadabortexception_class != 0);
1482 mono_defaults.thread_class = mono_class_from_name (
1483 mono_defaults.corlib, "System.Threading", "Thread");
1484 g_assert (mono_defaults.thread_class != 0);
1486 mono_defaults.internal_thread_class = mono_class_from_name (
1487 mono_defaults.corlib, "System.Threading", "InternalThread");
1488 if (!mono_defaults.internal_thread_class) {
1489 /* This can happen with an old mscorlib */
1490 fprintf (stderr, "Corlib too old for this runtime.\n");
1491 fprintf (stderr, "Loaded from: %s\n",
1492 mono_defaults.corlib? mono_image_get_filename (mono_defaults.corlib): "unknown");
1493 exit (1);
1496 mono_defaults.appdomain_class = mono_class_from_name (
1497 mono_defaults.corlib, "System", "AppDomain");
1498 g_assert (mono_defaults.appdomain_class != 0);
1500 mono_defaults.transparent_proxy_class = mono_class_from_name (
1501 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "TransparentProxy");
1502 g_assert (mono_defaults.transparent_proxy_class != 0);
1504 mono_defaults.real_proxy_class = mono_class_from_name (
1505 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "RealProxy");
1506 g_assert (mono_defaults.real_proxy_class != 0);
1508 mono_defaults.mono_method_message_class = mono_class_from_name (
1509 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", "MonoMethodMessage");
1510 g_assert (mono_defaults.mono_method_message_class != 0);
1512 mono_defaults.field_info_class = mono_class_from_name (
1513 mono_defaults.corlib, "System.Reflection", "FieldInfo");
1514 g_assert (mono_defaults.field_info_class != 0);
1516 mono_defaults.method_info_class = mono_class_from_name (
1517 mono_defaults.corlib, "System.Reflection", "MethodInfo");
1518 g_assert (mono_defaults.method_info_class != 0);
1520 mono_defaults.stringbuilder_class = mono_class_from_name (
1521 mono_defaults.corlib, "System.Text", "StringBuilder");
1522 g_assert (mono_defaults.stringbuilder_class != 0);
1524 mono_defaults.math_class = mono_class_from_name (
1525 mono_defaults.corlib, "System", "Math");
1526 g_assert (mono_defaults.math_class != 0);
1528 mono_defaults.stack_frame_class = mono_class_from_name (
1529 mono_defaults.corlib, "System.Diagnostics", "StackFrame");
1530 g_assert (mono_defaults.stack_frame_class != 0);
1532 mono_defaults.stack_trace_class = mono_class_from_name (
1533 mono_defaults.corlib, "System.Diagnostics", "StackTrace");
1534 g_assert (mono_defaults.stack_trace_class != 0);
1536 mono_defaults.marshal_class = mono_class_from_name (
1537 mono_defaults.corlib, "System.Runtime.InteropServices", "Marshal");
1538 g_assert (mono_defaults.marshal_class != 0);
1540 mono_defaults.iserializeable_class = mono_class_from_name (
1541 mono_defaults.corlib, "System.Runtime.Serialization", "ISerializable");
1542 g_assert (mono_defaults.iserializeable_class != 0);
1544 mono_defaults.serializationinfo_class = mono_class_from_name (
1545 mono_defaults.corlib, "System.Runtime.Serialization", "SerializationInfo");
1546 g_assert (mono_defaults.serializationinfo_class != 0);
1548 mono_defaults.streamingcontext_class = mono_class_from_name (
1549 mono_defaults.corlib, "System.Runtime.Serialization", "StreamingContext");
1550 g_assert (mono_defaults.streamingcontext_class != 0);
1552 mono_defaults.typed_reference_class = mono_class_from_name (
1553 mono_defaults.corlib, "System", "TypedReference");
1554 g_assert (mono_defaults.typed_reference_class != 0);
1556 mono_defaults.argumenthandle_class = mono_class_from_name (
1557 mono_defaults.corlib, "System", "RuntimeArgumentHandle");
1558 g_assert (mono_defaults.argumenthandle_class != 0);
1560 mono_defaults.marshalbyrefobject_class = mono_class_from_name (
1561 mono_defaults.corlib, "System", "MarshalByRefObject");
1562 g_assert (mono_defaults.marshalbyrefobject_class != 0);
1564 mono_defaults.monitor_class = mono_class_from_name (
1565 mono_defaults.corlib, "System.Threading", "Monitor");
1566 g_assert (mono_defaults.monitor_class != 0);
1568 mono_defaults.iremotingtypeinfo_class = mono_class_from_name (
1569 mono_defaults.corlib, "System.Runtime.Remoting", "IRemotingTypeInfo");
1570 g_assert (mono_defaults.iremotingtypeinfo_class != 0);
1572 mono_defaults.runtimesecurityframe_class = mono_class_from_name (
1573 mono_defaults.corlib, "System.Security", "RuntimeSecurityFrame");
1575 mono_defaults.executioncontext_class = mono_class_from_name (
1576 mono_defaults.corlib, "System.Threading", "ExecutionContext");
1578 mono_defaults.internals_visible_class = mono_class_from_name (
1579 mono_defaults.corlib, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute");
1581 mono_defaults.critical_finalizer_object = mono_class_from_name (
1582 mono_defaults.corlib, "System.Runtime.ConstrainedExecution", "CriticalFinalizerObject");
1585 * mscorlib needs a little help, only now it can load its friends list (after we have
1586 * loaded the InternalsVisibleToAttribute), load it now
1588 mono_assembly_load_friends (ass);
1590 mono_defaults.safehandle_class = mono_class_from_name (
1591 mono_defaults.corlib, "System.Runtime.InteropServices", "SafeHandle");
1593 mono_defaults.handleref_class = mono_class_from_name (
1594 mono_defaults.corlib, "System.Runtime.InteropServices", "HandleRef");
1596 mono_defaults.attribute_class = mono_class_from_name (
1597 mono_defaults.corlib, "System", "Attribute");
1599 mono_defaults.customattribute_data_class = mono_class_from_name (
1600 mono_defaults.corlib, "System.Reflection", "CustomAttributeData");
1602 /* these are initialized lazily when COM features are used */
1603 mono_defaults.variant_class = NULL;
1604 mono_defaults.com_object_class = NULL;
1605 mono_defaults.com_interop_proxy_class = NULL;
1606 mono_defaults.iunknown_class = NULL;
1607 mono_defaults.idispatch_class = NULL;
1610 * Note that mono_defaults.generic_*_class is only non-NULL if we're
1611 * using the 2.0 corlib.
1613 mono_class_init (mono_defaults.array_class);
1614 mono_defaults.generic_nullable_class = mono_class_from_name (
1615 mono_defaults.corlib, "System", "Nullable`1");
1616 mono_defaults.generic_ilist_class = mono_class_from_name (
1617 mono_defaults.corlib, "System.Collections.Generic", "IList`1");
1619 domain->friendly_name = g_path_get_basename (filename);
1621 _mono_debug_init_corlib (domain);
1623 return domain;
1627 * mono_init:
1629 * Creates the initial application domain and initializes the mono_defaults
1630 * structure.
1631 * This function is guaranteed to not run any IL code.
1632 * The runtime is initialized using the default runtime version.
1634 * Returns: the initial domain.
1636 MonoDomain *
1637 mono_init (const char *domain_name)
1639 return mono_init_internal (domain_name, NULL, DEFAULT_RUNTIME_VERSION);
1643 * mono_init_from_assembly:
1644 * @domain_name: name to give to the initial domain
1645 * @filename: filename to load on startup
1647 * Used by the runtime, users should use mono_jit_init instead.
1649 * Creates the initial application domain and initializes the mono_defaults
1650 * structure.
1651 * This function is guaranteed to not run any IL code.
1652 * The runtime is initialized using the runtime version required by the
1653 * provided executable. The version is determined by looking at the exe
1654 * configuration file and the version PE field)
1656 * Returns: the initial domain.
1658 MonoDomain *
1659 mono_init_from_assembly (const char *domain_name, const char *filename)
1661 return mono_init_internal (domain_name, filename, NULL);
1665 * mono_init_version:
1667 * Used by the runtime, users should use mono_jit_init instead.
1669 * Creates the initial application domain and initializes the mono_defaults
1670 * structure.
1672 * This function is guaranteed to not run any IL code.
1673 * The runtime is initialized using the provided rutime version.
1675 * Returns: the initial domain.
1677 MonoDomain *
1678 mono_init_version (const char *domain_name, const char *version)
1680 return mono_init_internal (domain_name, NULL, version);
1684 * mono_init_com_types:
1686 * Initializes all types needed for COM Interop in mono_defaults structure.
1688 void
1689 mono_init_com_types (void)
1691 static gboolean initialized = FALSE;
1693 if (initialized)
1694 return;
1696 /* FIXME: do I need some threading protection here */
1698 g_assert (mono_defaults.corlib);
1700 mono_defaults.variant_class = mono_class_from_name (
1701 mono_defaults.corlib, "System", "Variant");
1702 g_assert (mono_defaults.variant_class != 0);
1704 mono_defaults.com_object_class = mono_class_from_name (
1705 mono_defaults.corlib, "System", "__ComObject");
1706 g_assert (mono_defaults.com_object_class != 0);
1708 mono_defaults.com_interop_proxy_class = mono_class_from_name (
1709 mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
1710 g_assert (mono_defaults.com_interop_proxy_class != 0);
1712 mono_defaults.iunknown_class = mono_class_from_name (
1713 mono_defaults.corlib, "Mono.Interop", "IUnknown");
1714 g_assert (mono_defaults.iunknown_class != 0);
1716 mono_defaults.idispatch_class = mono_class_from_name (
1717 mono_defaults.corlib, "Mono.Interop", "IDispatch");
1718 g_assert (mono_defaults.idispatch_class != 0);
1720 initialized = TRUE;
1724 * mono_cleanup:
1726 * Cleans up all metadata modules.
1728 void
1729 mono_cleanup (void)
1731 mono_close_exe_image ();
1733 mono_loader_cleanup ();
1734 mono_classes_cleanup ();
1735 mono_assemblies_cleanup ();
1736 mono_images_cleanup ();
1737 mono_debug_cleanup ();
1738 mono_metadata_cleanup ();
1740 TlsFree (appdomain_thread_id);
1741 DeleteCriticalSection (&appdomains_mutex);
1744 void
1745 mono_close_exe_image (void)
1747 if (exe_image)
1748 mono_image_close (exe_image);
1752 * mono_get_root_domain:
1754 * The root AppDomain is the initial domain created by the runtime when it is
1755 * initialized. Programs execute on this AppDomain, but can create new ones
1756 * later. Currently there is no unmanaged API to create new AppDomains, this
1757 * must be done from managed code.
1759 * Returns: the root appdomain, to obtain the current domain, use mono_domain_get ()
1761 MonoDomain*
1762 mono_get_root_domain (void)
1764 return mono_root_domain;
1768 * mono_domain_get:
1770 * Returns: the current domain, to obtain the root domain use
1771 * mono_get_root_domain().
1773 MonoDomain *
1774 mono_domain_get ()
1776 return GET_APPDOMAIN ();
1779 void
1780 mono_domain_unset (void)
1782 SET_APPDOMAIN (NULL);
1785 void
1786 mono_domain_set_internal_with_options (MonoDomain *domain, gboolean migrate_exception)
1788 MonoInternalThread *thread;
1790 if (mono_domain_get () == domain)
1791 return;
1793 SET_APPDOMAIN (domain);
1794 SET_APPCONTEXT (domain->default_context);
1796 if (migrate_exception) {
1797 thread = mono_thread_internal_current ();
1798 if (!thread->abort_exc)
1799 return;
1801 g_assert (thread->abort_exc->object.vtable->domain != domain);
1802 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
1803 g_assert (thread->abort_exc->object.vtable->domain == domain);
1808 * mono_domain_set_internal:
1809 * @domain: the new domain
1811 * Sets the current domain to @domain.
1813 void
1814 mono_domain_set_internal (MonoDomain *domain)
1816 mono_domain_set_internal_with_options (domain, TRUE);
1819 void
1820 mono_domain_foreach (MonoDomainFunc func, gpointer user_data)
1822 int i, size;
1823 MonoDomain **copy;
1826 * Create a copy of the data to avoid calling the user callback
1827 * inside the lock because that could lead to deadlocks.
1828 * We can do this because this function is not perf. critical.
1830 mono_appdomains_lock ();
1831 size = appdomain_list_size;
1832 copy = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1833 memcpy (copy, appdomains_list, appdomain_list_size * sizeof (void*));
1834 mono_appdomains_unlock ();
1836 for (i = 0; i < size; ++i) {
1837 if (copy [i])
1838 func (copy [i], user_data);
1841 mono_gc_free_fixed (copy);
1845 * mono_domain_assembly_open:
1846 * @domain: the application domain
1847 * @name: file name of the assembly
1849 * fixme: maybe we should integrate this with mono_assembly_open ??
1851 MonoAssembly *
1852 mono_domain_assembly_open (MonoDomain *domain, const char *name)
1854 MonoDomain *current;
1855 MonoAssembly *ass;
1856 GSList *tmp;
1858 mono_domain_assemblies_lock (domain);
1859 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1860 ass = tmp->data;
1861 if (strcmp (name, ass->aname.name) == 0) {
1862 mono_domain_assemblies_unlock (domain);
1863 return ass;
1866 mono_domain_assemblies_unlock (domain);
1868 if (domain != mono_domain_get ()) {
1869 current = mono_domain_get ();
1871 mono_domain_set (domain, FALSE);
1872 ass = mono_assembly_open (name, NULL);
1873 mono_domain_set (current, FALSE);
1874 } else {
1875 ass = mono_assembly_open (name, NULL);
1878 return ass;
1881 #ifndef HAVE_SGEN_GC
1882 static void
1883 free_slist (gpointer key, gpointer value, gpointer user_data)
1885 g_slist_free (value);
1887 #endif
1889 #if HAVE_SGEN_GC
1890 static void
1891 unregister_vtable_reflection_type (MonoVTable *vtable)
1893 MonoObject *type = vtable->type;
1895 if (type->vtable->klass != mono_defaults.monotype_class)
1896 mono_gc_deregister_root ((char*)&vtable->type);
1898 #endif
1900 void
1901 mono_domain_free (MonoDomain *domain, gboolean force)
1903 int code_size, code_alloc;
1904 GSList *tmp;
1905 if ((domain == mono_root_domain) && !force) {
1906 g_warning ("cant unload root domain");
1907 return;
1910 if (mono_dont_free_domains)
1911 return;
1913 mono_profiler_appdomain_event (domain, MONO_PROFILE_START_UNLOAD);
1915 mono_debug_domain_unload (domain);
1917 mono_appdomains_lock ();
1918 appdomains_list [domain->domain_id] = NULL;
1919 mono_appdomains_unlock ();
1921 /* must do this early as it accesses fields and types */
1922 if (domain->special_static_fields) {
1923 mono_alloc_special_static_data_free (domain->special_static_fields);
1924 g_hash_table_destroy (domain->special_static_fields);
1925 domain->special_static_fields = NULL;
1929 * We must destroy all these hash tables here because they
1930 * contain references to managed objects belonging to the
1931 * domain. Once we let the GC clear the domain there must be
1932 * no more such references, or we'll crash if a collection
1933 * occurs.
1935 mono_g_hash_table_destroy (domain->ldstr_table);
1936 domain->ldstr_table = NULL;
1938 mono_g_hash_table_destroy (domain->env);
1939 domain->env = NULL;
1941 mono_reflection_cleanup_domain (domain);
1943 if (domain->type_hash) {
1944 mono_g_hash_table_destroy (domain->type_hash);
1945 domain->type_hash = NULL;
1947 if (domain->type_init_exception_hash) {
1948 mono_g_hash_table_destroy (domain->type_init_exception_hash);
1949 domain->type_init_exception_hash = NULL;
1952 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1953 MonoAssembly *ass = tmp->data;
1954 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);
1955 if (!mono_assembly_close_except_image_pools (ass))
1956 tmp->data = NULL;
1959 #if HAVE_SGEN_GC
1960 if (domain->class_vtable_array) {
1961 int i;
1962 for (i = 0; i < domain->class_vtable_array->len; ++i)
1963 unregister_vtable_reflection_type (g_ptr_array_index (domain->class_vtable_array, i));
1965 #endif
1967 mono_gc_clear_domain (domain);
1969 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1970 MonoAssembly *ass = tmp->data;
1971 if (ass)
1972 mono_assembly_close_finish (ass);
1974 g_slist_free (domain->domain_assemblies);
1975 domain->domain_assemblies = NULL;
1978 * Send this after the assemblies have been unloaded and the domain is still in a
1979 * usable state.
1981 mono_profiler_appdomain_event (domain, MONO_PROFILE_END_UNLOAD);
1983 if (free_domain_hook)
1984 free_domain_hook (domain);
1986 /* FIXME: free delegate_hash_table when it's used */
1987 if (domain->search_path) {
1988 g_strfreev (domain->search_path);
1989 domain->search_path = NULL;
1991 domain->create_proxy_for_type_method = NULL;
1992 domain->private_invoke_method = NULL;
1993 domain->default_context = NULL;
1994 domain->out_of_memory_ex = NULL;
1995 domain->null_reference_ex = NULL;
1996 domain->stack_overflow_ex = NULL;
1997 domain->ephemeron_tombstone = NULL;
1998 domain->entry_assembly = NULL;
2000 g_free (domain->friendly_name);
2001 domain->friendly_name = NULL;
2002 g_ptr_array_free (domain->class_vtable_array, TRUE);
2003 domain->class_vtable_array = NULL;
2004 g_hash_table_destroy (domain->proxy_vtable_hash);
2005 domain->proxy_vtable_hash = NULL;
2006 if (domain->static_data_array) {
2007 mono_gc_free_fixed (domain->static_data_array);
2008 domain->static_data_array = NULL;
2010 mono_internal_hash_table_destroy (&domain->jit_code_hash);
2013 * There might still be jit info tables of this domain which
2014 * are not freed. Since the domain cannot be in use anymore,
2015 * this will free them.
2017 mono_thread_hazardous_try_free_all ();
2018 g_assert (domain->num_jit_info_tables == 1);
2019 jit_info_table_free (domain->jit_info_table);
2020 domain->jit_info_table = NULL;
2021 g_assert (!domain->jit_info_free_queue);
2023 /* collect statistics */
2024 code_alloc = mono_code_manager_size (domain->code_mp, &code_size);
2025 total_domain_code_alloc += code_alloc;
2026 max_domain_code_alloc = MAX (max_domain_code_alloc, code_alloc);
2027 max_domain_code_size = MAX (max_domain_code_size, code_size);
2029 #ifdef DEBUG_DOMAIN_UNLOAD
2030 mono_mempool_invalidate (domain->mp);
2031 mono_code_manager_invalidate (domain->code_mp);
2032 #else
2033 mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (domain->mp);
2034 mono_mempool_destroy (domain->mp);
2035 domain->mp = NULL;
2036 mono_code_manager_destroy (domain->code_mp);
2037 domain->code_mp = NULL;
2038 #endif
2040 g_hash_table_destroy (domain->finalizable_objects_hash);
2041 domain->finalizable_objects_hash = NULL;
2042 #ifndef HAVE_SGEN_GC
2043 if (domain->track_resurrection_objects_hash) {
2044 g_hash_table_foreach (domain->track_resurrection_objects_hash, free_slist, NULL);
2045 g_hash_table_destroy (domain->track_resurrection_objects_hash);
2047 if (domain->track_resurrection_handles_hash)
2048 g_hash_table_destroy (domain->track_resurrection_handles_hash);
2049 #endif
2050 if (domain->method_rgctx_hash) {
2051 g_hash_table_destroy (domain->method_rgctx_hash);
2052 domain->method_rgctx_hash = NULL;
2054 if (domain->generic_virtual_cases) {
2055 g_hash_table_destroy (domain->generic_virtual_cases);
2056 domain->generic_virtual_cases = NULL;
2059 DeleteCriticalSection (&domain->finalizable_objects_hash_lock);
2060 DeleteCriticalSection (&domain->assemblies_lock);
2061 DeleteCriticalSection (&domain->jit_code_hash_lock);
2062 DeleteCriticalSection (&domain->lock);
2063 domain->setup = NULL;
2065 mono_gc_deregister_root ((char*)&(domain->MONO_DOMAIN_FIRST_GC_TRACKED));
2067 /* FIXME: anything else required ? */
2069 mono_gc_free_fixed (domain);
2071 mono_perfcounters->loader_appdomains--;
2073 if ((domain == mono_root_domain))
2074 mono_root_domain = NULL;
2078 * mono_domain_get_id:
2079 * @domainid: the ID
2081 * Returns: the a domain for a specific domain id.
2083 MonoDomain *
2084 mono_domain_get_by_id (gint32 domainid)
2086 MonoDomain * domain;
2088 mono_appdomains_lock ();
2089 if (domainid < appdomain_list_size)
2090 domain = appdomains_list [domainid];
2091 else
2092 domain = NULL;
2093 mono_appdomains_unlock ();
2095 return domain;
2098 gint32
2099 mono_domain_get_id (MonoDomain *domain)
2101 return domain->domain_id;
2105 * mono_domain_alloc:
2107 * LOCKING: Acquires the domain lock.
2109 gpointer
2110 mono_domain_alloc (MonoDomain *domain, guint size)
2112 gpointer res;
2114 mono_domain_lock (domain);
2115 mono_perfcounters->loader_bytes += size;
2116 res = mono_mempool_alloc (domain->mp, size);
2117 mono_domain_unlock (domain);
2119 return res;
2123 * mono_domain_alloc0:
2125 * LOCKING: Acquires the domain lock.
2127 gpointer
2128 mono_domain_alloc0 (MonoDomain *domain, guint size)
2130 gpointer res;
2132 mono_domain_lock (domain);
2133 mono_perfcounters->loader_bytes += size;
2134 res = mono_mempool_alloc0 (domain->mp, size);
2135 mono_domain_unlock (domain);
2137 return res;
2141 * mono_domain_code_reserve:
2143 * LOCKING: Acquires the domain lock.
2145 void*
2146 mono_domain_code_reserve (MonoDomain *domain, int size)
2148 gpointer res;
2150 mono_domain_lock (domain);
2151 res = mono_code_manager_reserve (domain->code_mp, size);
2152 mono_domain_unlock (domain);
2154 return res;
2158 * mono_domain_code_reserve_align:
2160 * LOCKING: Acquires the domain lock.
2162 void*
2163 mono_domain_code_reserve_align (MonoDomain *domain, int size, int alignment)
2165 gpointer res;
2167 mono_domain_lock (domain);
2168 res = mono_code_manager_reserve_align (domain->code_mp, size, alignment);
2169 mono_domain_unlock (domain);
2171 return res;
2175 * mono_domain_code_commit:
2177 * LOCKING: Acquires the domain lock.
2179 void
2180 mono_domain_code_commit (MonoDomain *domain, void *data, int size, int newsize)
2182 mono_domain_lock (domain);
2183 mono_code_manager_commit (domain->code_mp, data, size, newsize);
2184 mono_domain_unlock (domain);
2188 * mono_domain_code_foreach:
2189 * Iterate over the code thunks of the code manager of @domain.
2191 * The @func callback MUST not take any locks. If it really needs to, it must respect
2192 * the locking rules of the runtime: http://www.mono-project.com/Mono:Runtime:Documentation:ThreadSafety
2193 * LOCKING: Acquires the domain lock.
2196 void
2197 mono_domain_code_foreach (MonoDomain *domain, MonoCodeManagerFunc func, void *user_data)
2199 mono_domain_lock (domain);
2200 mono_code_manager_foreach (domain->code_mp, func, user_data);
2201 mono_domain_unlock (domain);
2205 void
2206 mono_context_set (MonoAppContext * new_context)
2208 SET_APPCONTEXT (new_context);
2211 MonoAppContext *
2212 mono_context_get (void)
2214 return GET_APPCONTEXT ();
2217 /* LOCKING: the caller holds the lock for this domain */
2218 void
2219 mono_domain_add_class_static_data (MonoDomain *domain, MonoClass *klass, gpointer data, guint32 *bitmap)
2221 /* The first entry in the array is the index of the next free slot
2222 * and the total size of the array
2224 int next;
2225 if (domain->static_data_array) {
2226 int size = GPOINTER_TO_INT (domain->static_data_array [1]);
2227 next = GPOINTER_TO_INT (domain->static_data_array [0]);
2228 if (next >= size) {
2229 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * (size * 2), NULL);
2230 memcpy (new_array, domain->static_data_array, sizeof (gpointer) * size);
2231 size *= 2;
2232 new_array [1] = GINT_TO_POINTER (size);
2233 mono_gc_free_fixed (domain->static_data_array);
2234 domain->static_data_array = new_array;
2236 } else {
2237 int size = 32;
2238 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * size, NULL);
2239 next = 2;
2240 new_array [0] = GINT_TO_POINTER (next);
2241 new_array [1] = GINT_TO_POINTER (size);
2242 domain->static_data_array = new_array;
2244 domain->static_data_array [next++] = data;
2245 domain->static_data_array [0] = GINT_TO_POINTER (next);
2248 MonoImage*
2249 mono_get_corlib (void)
2251 return mono_defaults.corlib;
2254 MonoClass*
2255 mono_get_object_class (void)
2257 return mono_defaults.object_class;
2260 MonoClass*
2261 mono_get_byte_class (void)
2263 return mono_defaults.byte_class;
2266 MonoClass*
2267 mono_get_void_class (void)
2269 return mono_defaults.void_class;
2272 MonoClass*
2273 mono_get_boolean_class (void)
2275 return mono_defaults.boolean_class;
2278 MonoClass*
2279 mono_get_sbyte_class (void)
2281 return mono_defaults.sbyte_class;
2284 MonoClass*
2285 mono_get_int16_class (void)
2287 return mono_defaults.int16_class;
2290 MonoClass*
2291 mono_get_uint16_class (void)
2293 return mono_defaults.uint16_class;
2296 MonoClass*
2297 mono_get_int32_class (void)
2299 return mono_defaults.int32_class;
2302 MonoClass*
2303 mono_get_uint32_class (void)
2305 return mono_defaults.uint32_class;
2308 MonoClass*
2309 mono_get_intptr_class (void)
2311 return mono_defaults.int_class;
2314 MonoClass*
2315 mono_get_uintptr_class (void)
2317 return mono_defaults.uint_class;
2320 MonoClass*
2321 mono_get_int64_class (void)
2323 return mono_defaults.int64_class;
2326 MonoClass*
2327 mono_get_uint64_class (void)
2329 return mono_defaults.uint64_class;
2332 MonoClass*
2333 mono_get_single_class (void)
2335 return mono_defaults.single_class;
2338 MonoClass*
2339 mono_get_double_class (void)
2341 return mono_defaults.double_class;
2344 MonoClass*
2345 mono_get_char_class (void)
2347 return mono_defaults.char_class;
2350 MonoClass*
2351 mono_get_string_class (void)
2353 return mono_defaults.string_class;
2356 MonoClass*
2357 mono_get_enum_class (void)
2359 return mono_defaults.enum_class;
2362 MonoClass*
2363 mono_get_array_class (void)
2365 return mono_defaults.array_class;
2368 MonoClass*
2369 mono_get_thread_class (void)
2371 return mono_defaults.thread_class;
2374 MonoClass*
2375 mono_get_exception_class (void)
2377 return mono_defaults.exception_class;
2381 static char* get_attribute_value (const gchar **attribute_names,
2382 const gchar **attribute_values,
2383 const char *att_name)
2385 int n;
2386 for (n=0; attribute_names[n] != NULL; n++) {
2387 if (strcmp (attribute_names[n], att_name) == 0)
2388 return g_strdup (attribute_values[n]);
2390 return NULL;
2393 static void start_element (GMarkupParseContext *context,
2394 const gchar *element_name,
2395 const gchar **attribute_names,
2396 const gchar **attribute_values,
2397 gpointer user_data,
2398 GError **error)
2400 AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2402 if (strcmp (element_name, "configuration") == 0) {
2403 app_config->configuration_count++;
2404 return;
2406 if (strcmp (element_name, "startup") == 0) {
2407 app_config->startup_count++;
2408 return;
2411 if (app_config->configuration_count != 1 || app_config->startup_count != 1)
2412 return;
2414 if (strcmp (element_name, "requiredRuntime") == 0) {
2415 app_config->required_runtime = get_attribute_value (attribute_names, attribute_values, "version");
2416 } else if (strcmp (element_name, "supportedRuntime") == 0) {
2417 char *version = get_attribute_value (attribute_names, attribute_values, "version");
2418 app_config->supported_runtimes = g_slist_append (app_config->supported_runtimes, version);
2422 static void end_element (GMarkupParseContext *context,
2423 const gchar *element_name,
2424 gpointer user_data,
2425 GError **error)
2427 AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2429 if (strcmp (element_name, "configuration") == 0) {
2430 app_config->configuration_count--;
2431 } else if (strcmp (element_name, "startup") == 0) {
2432 app_config->startup_count--;
2436 static const GMarkupParser
2437 mono_parser = {
2438 start_element,
2439 end_element,
2440 NULL,
2441 NULL,
2442 NULL
2445 static AppConfigInfo *
2446 app_config_parse (const char *exe_filename)
2448 AppConfigInfo *app_config;
2449 GMarkupParseContext *context;
2450 char *text;
2451 gsize len;
2452 const char *bundled_config;
2453 char *config_filename;
2455 bundled_config = mono_config_string_for_assembly_file (exe_filename);
2457 if (bundled_config) {
2458 text = g_strdup (bundled_config);
2459 len = strlen (text);
2460 } else {
2461 config_filename = g_strconcat (exe_filename, ".config", NULL);
2463 if (!g_file_get_contents (config_filename, &text, &len, NULL)) {
2464 g_free (config_filename);
2465 return NULL;
2467 g_free (config_filename);
2470 app_config = g_new0 (AppConfigInfo, 1);
2472 context = g_markup_parse_context_new (&mono_parser, 0, app_config, NULL);
2473 if (g_markup_parse_context_parse (context, text, len, NULL)) {
2474 g_markup_parse_context_end_parse (context, NULL);
2476 g_markup_parse_context_free (context);
2477 g_free (text);
2478 return app_config;
2481 static void
2482 app_config_free (AppConfigInfo* app_config)
2484 char *rt;
2485 GSList *list = app_config->supported_runtimes;
2486 while (list != NULL) {
2487 rt = (char*)list->data;
2488 g_free (rt);
2489 list = g_slist_next (list);
2491 g_slist_free (app_config->supported_runtimes);
2492 g_free (app_config->required_runtime);
2493 g_free (app_config);
2497 static const MonoRuntimeInfo*
2498 get_runtime_by_version (const char *version)
2500 int n;
2501 int max = G_N_ELEMENTS (supported_runtimes);
2503 for (n=0; n<max; n++) {
2504 if (strcmp (version, supported_runtimes[n].runtime_version) == 0)
2505 return &supported_runtimes[n];
2507 return NULL;
2510 static void
2511 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes)
2513 AppConfigInfo* app_config;
2514 char *version;
2515 const MonoRuntimeInfo* runtime = NULL;
2516 MonoImage *image = NULL;
2518 app_config = app_config_parse (exe_file);
2520 if (app_config != NULL) {
2521 /* Check supportedRuntime elements, if none is supported, fail.
2522 * If there are no such elements, look for a requiredRuntime element.
2524 if (app_config->supported_runtimes != NULL) {
2525 int n = 0;
2526 GSList *list = app_config->supported_runtimes;
2527 while (list != NULL) {
2528 version = (char*) list->data;
2529 runtime = get_runtime_by_version (version);
2530 if (runtime != NULL)
2531 runtimes [n++] = runtime;
2532 list = g_slist_next (list);
2534 runtimes [n] = NULL;
2535 app_config_free (app_config);
2536 return;
2539 /* Check the requiredRuntime element. This is for 1.0 apps only. */
2540 if (app_config->required_runtime != NULL) {
2541 runtimes [0] = get_runtime_by_version (app_config->required_runtime);
2542 runtimes [1] = NULL;
2543 app_config_free (app_config);
2544 return;
2546 app_config_free (app_config);
2549 /* Look for a runtime with the exact version */
2550 image = mono_assembly_open_from_bundle (exe_file, NULL, FALSE);
2552 if (image == NULL)
2553 image = mono_image_open (exe_file, NULL);
2555 if (image == NULL) {
2556 /* The image is wrong or the file was not found. In this case return
2557 * a default runtime and leave to the initialization method the work of
2558 * reporting the error.
2560 runtimes [0] = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
2561 runtimes [1] = NULL;
2562 return;
2565 *exe_image = image;
2567 runtimes [0] = get_runtime_by_version (image->version);
2568 runtimes [1] = NULL;
2573 * mono_get_runtime_info:
2575 * Returns: the version of the current runtime instance.
2577 const MonoRuntimeInfo*
2578 mono_get_runtime_info (void)
2580 return current_runtime;
2583 gchar *
2584 mono_debugger_check_runtime_version (const char *filename)
2586 const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
2587 const MonoRuntimeInfo *rinfo;
2588 MonoImage *image;
2590 get_runtimes_from_exe (filename, &image, runtimes);
2591 rinfo = runtimes [0];
2593 if (!rinfo)
2594 return g_strdup_printf ("Cannot get runtime version from assembly `%s'", filename);
2596 if (rinfo != current_runtime)
2597 return g_strdup_printf ("The Mono Debugger is currently using the `%s' runtime, but "
2598 "the assembly `%s' requires version `%s'", current_runtime->runtime_version,
2599 filename, rinfo->runtime_version);
2601 return NULL;
2605 * mono_framework_version:
2607 * Return the major version of the framework curently executing.
2610 mono_framework_version (void)
2612 return current_runtime->framework_version [0] - '0';