2010-02-19 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / metadata / domain.c
blobecffce957430ff84f0760547447e7fb8989d89ea
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.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 {"v1.0.3705", "1.0", { {1,0,5000,0}, {7,0,5000,0} } },
132 {"v1.1.4322", "1.0", { {1,0,5000,0}, {7,0,5000,0} } },
133 {"v2.0.50215","2.0", { {2,0,0,0}, {8,0,0,0} } },
134 {"v2.0.50727","2.0", { {2,0,0,0}, {8,0,0,0} } },
135 {"v4.0.21006","4.0", { {4,0,0,0}, {10,0,0,0} } },
136 {"v4.0.30128","4.0", { {4,0,0,0}, {10,0,0,0} } },
137 {"moonlight", "2.1", { {2,0,5,0}, {9,0,0,0} } },
141 /* The stable runtime version */
142 #define DEFAULT_RUNTIME_VERSION "v2.0.50727"
144 /* Callbacks installed by the JIT */
145 static MonoCreateDomainFunc create_domain_hook;
146 static MonoFreeDomainFunc free_domain_hook;
148 /* This is intentionally not in the header file, so people don't misuse it. */
149 extern void _mono_debug_init_corlib (MonoDomain *domain);
151 static void
152 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes);
154 static const MonoRuntimeInfo*
155 get_runtime_by_version (const char *version);
157 static MonoImage*
158 mono_jit_info_find_aot_module (guint8* addr);
160 guint32
161 mono_domain_get_tls_key (void)
163 #ifdef NO_TLS_SET_VALUE
164 g_assert_not_reached ();
165 return 0;
166 #else
167 return appdomain_thread_id;
168 #endif
171 gint32
172 mono_domain_get_tls_offset (void)
174 int offset = -1;
175 MONO_THREAD_VAR_OFFSET (tls_appdomain, offset);
176 /* __asm ("jmp 1f; .section writetext, \"awx\"; 1: movl $tls_appdomain@ntpoff, %0; jmp 2f; .previous; 2:"
177 : "=r" (offset));*/
178 return offset;
181 #define JIT_INFO_TABLE_FILL_RATIO_NOM 3
182 #define JIT_INFO_TABLE_FILL_RATIO_DENOM 4
183 #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)
185 #define JIT_INFO_TABLE_LOW_WATERMARK(n) ((n) / 2)
186 #define JIT_INFO_TABLE_HIGH_WATERMARK(n) ((n) * 5 / 6)
188 #define JIT_INFO_TOMBSTONE_MARKER ((MonoMethod*)NULL)
189 #define IS_JIT_INFO_TOMBSTONE(ji) ((ji)->method == JIT_INFO_TOMBSTONE_MARKER)
191 #define JIT_INFO_TABLE_HAZARD_INDEX 0
192 #define JIT_INFO_HAZARD_INDEX 1
194 static int
195 jit_info_table_num_elements (MonoJitInfoTable *table)
197 int i;
198 int num_elements = 0;
200 for (i = 0; i < table->num_chunks; ++i) {
201 MonoJitInfoTableChunk *chunk = table->chunks [i];
202 int chunk_num_elements = chunk->num_elements;
203 int j;
205 for (j = 0; j < chunk_num_elements; ++j) {
206 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j]))
207 ++num_elements;
211 return num_elements;
214 static MonoJitInfoTableChunk*
215 jit_info_table_new_chunk (void)
217 MonoJitInfoTableChunk *chunk = g_new0 (MonoJitInfoTableChunk, 1);
218 chunk->refcount = 1;
220 return chunk;
223 static MonoJitInfoTable *
224 jit_info_table_new (MonoDomain *domain)
226 MonoJitInfoTable *table = g_malloc0 (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*));
228 table->domain = domain;
229 table->num_chunks = 1;
230 table->chunks [0] = jit_info_table_new_chunk ();
232 return table;
235 static void
236 jit_info_table_free (MonoJitInfoTable *table)
238 int i;
239 int num_chunks = table->num_chunks;
240 MonoDomain *domain = table->domain;
242 mono_domain_lock (domain);
244 table->domain->num_jit_info_tables--;
245 if (table->domain->num_jit_info_tables <= 1) {
246 GSList *list;
248 for (list = table->domain->jit_info_free_queue; list; list = list->next)
249 g_free (list->data);
251 g_slist_free (table->domain->jit_info_free_queue);
252 table->domain->jit_info_free_queue = NULL;
255 /* At this point we assume that there are no other threads
256 still accessing the table, so we don't have to worry about
257 hazardous pointers. */
259 for (i = 0; i < num_chunks; ++i) {
260 MonoJitInfoTableChunk *chunk = table->chunks [i];
261 int num_elements;
262 int j;
264 if (--chunk->refcount > 0)
265 continue;
267 num_elements = chunk->num_elements;
268 for (j = 0; j < num_elements; ++j) {
269 MonoJitInfo *ji = chunk->data [j];
271 if (IS_JIT_INFO_TOMBSTONE (ji))
272 g_free (ji);
275 g_free (chunk);
278 mono_domain_unlock (domain);
280 g_free (table);
283 /* Can be called with hp==NULL, in which case it acts as an ordinary
284 pointer fetch. It's used that way indirectly from
285 mono_jit_info_table_add(), which doesn't have to care about hazards
286 because it holds the respective domain lock. */
287 static gpointer
288 get_hazardous_pointer (gpointer volatile *pp, MonoThreadHazardPointers *hp, int hazard_index)
290 gpointer p;
292 for (;;) {
293 /* Get the pointer */
294 p = *pp;
295 /* If we don't have hazard pointers just return the
296 pointer. */
297 if (!hp)
298 return p;
299 /* Make it hazardous */
300 mono_hazard_pointer_set (hp, hazard_index, p);
301 /* Check that it's still the same. If not, try
302 again. */
303 if (*pp != p) {
304 mono_hazard_pointer_clear (hp, hazard_index);
305 continue;
307 break;
310 return p;
313 /* The jit_info_table is sorted in ascending order by the end
314 * addresses of the compiled methods. The reason why we have to do
315 * this is that once we introduce tombstones, it becomes possible for
316 * code ranges to overlap, and if we sort by code start and insert at
317 * the back of the table, we cannot guarantee that we won't overlook
318 * an entry.
320 * There are actually two possible ways to do the sorting and
321 * inserting which work with our lock-free mechanism:
323 * 1. Sort by start address and insert at the front. When looking for
324 * an entry, find the last one with a start address lower than the one
325 * you're looking for, then work your way to the front of the table.
327 * 2. Sort by end address and insert at the back. When looking for an
328 * entry, find the first one with an end address higher than the one
329 * you're looking for, then work your way to the end of the table.
331 * We chose the latter out of convenience.
333 static int
334 jit_info_table_index (MonoJitInfoTable *table, gint8 *addr)
336 int left = 0, right = table->num_chunks;
338 g_assert (left < right);
340 do {
341 int pos = (left + right) / 2;
342 MonoJitInfoTableChunk *chunk = table->chunks [pos];
344 if (addr < chunk->last_code_end)
345 right = pos;
346 else
347 left = pos + 1;
348 } while (left < right);
349 g_assert (left == right);
351 if (left >= table->num_chunks)
352 return table->num_chunks - 1;
353 return left;
356 static int
357 jit_info_table_chunk_index (MonoJitInfoTableChunk *chunk, MonoThreadHazardPointers *hp, gint8 *addr)
359 int left = 0, right = chunk->num_elements;
361 while (left < right) {
362 int pos = (left + right) / 2;
363 MonoJitInfo *ji = get_hazardous_pointer((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
364 gint8 *code_end = (gint8*)ji->code_start + ji->code_size;
366 if (addr < code_end)
367 right = pos;
368 else
369 left = pos + 1;
371 g_assert (left == right);
373 return left;
376 MonoJitInfo*
377 mono_jit_info_table_find (MonoDomain *domain, char *addr)
379 MonoJitInfoTable *table;
380 MonoJitInfo *ji;
381 int chunk_pos, pos;
382 MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
383 MonoImage *image;
385 ++mono_stats.jit_info_table_lookup_count;
387 /* First we have to get the domain's jit_info_table. This is
388 complicated by the fact that a writer might substitute a
389 new table and free the old one. What the writer guarantees
390 us is that it looks at the hazard pointers after it has
391 changed the jit_info_table pointer. So, if we guard the
392 table by a hazard pointer and make sure that the pointer is
393 still there after we've made it hazardous, we don't have to
394 worry about the writer freeing the table. */
395 table = get_hazardous_pointer ((gpointer volatile*)&domain->jit_info_table, hp, JIT_INFO_TABLE_HAZARD_INDEX);
397 chunk_pos = jit_info_table_index (table, (gint8*)addr);
398 g_assert (chunk_pos < table->num_chunks);
400 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], hp, (gint8*)addr);
402 /* We now have a position that's very close to that of the
403 first element whose end address is higher than the one
404 we're looking for. If we don't have the exact position,
405 then we have a position below that one, so we'll just
406 search upward until we find our element. */
407 do {
408 MonoJitInfoTableChunk *chunk = table->chunks [chunk_pos];
410 while (pos < chunk->num_elements) {
411 ji = get_hazardous_pointer ((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
413 ++pos;
415 if (IS_JIT_INFO_TOMBSTONE (ji)) {
416 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
417 continue;
419 if ((gint8*)addr >= (gint8*)ji->code_start
420 && (gint8*)addr < (gint8*)ji->code_start + ji->code_size) {
421 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
422 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
423 return ji;
426 /* If we find a non-tombstone element which is already
427 beyond what we're looking for, we have to end the
428 search. */
429 if ((gint8*)addr < (gint8*)ji->code_start)
430 goto not_found;
433 ++chunk_pos;
434 pos = 0;
435 } while (chunk_pos < table->num_chunks);
437 not_found:
438 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
439 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
441 ji = NULL;
443 /* Maybe its an AOT module */
444 image = mono_jit_info_find_aot_module ((guint8*)addr);
445 if (image)
446 ji = jit_info_find_in_aot_func (domain, image, addr);
448 return ji;
451 static G_GNUC_UNUSED void
452 jit_info_table_check (MonoJitInfoTable *table)
454 int i;
456 for (i = 0; i < table->num_chunks; ++i) {
457 MonoJitInfoTableChunk *chunk = table->chunks [i];
458 int j;
460 g_assert (chunk->refcount > 0 /* && chunk->refcount <= 8 */);
461 if (chunk->refcount > 10)
462 printf("warning: chunk refcount is %d\n", chunk->refcount);
463 g_assert (chunk->num_elements <= MONO_JIT_INFO_TABLE_CHUNK_SIZE);
465 for (j = 0; j < chunk->num_elements; ++j) {
466 MonoJitInfo *this = chunk->data [j];
467 MonoJitInfo *next;
469 g_assert ((gint8*)this->code_start + this->code_size <= chunk->last_code_end);
471 if (j < chunk->num_elements - 1)
472 next = chunk->data [j + 1];
473 else if (i < table->num_chunks - 1) {
474 int k;
476 for (k = i + 1; k < table->num_chunks; ++k)
477 if (table->chunks [k]->num_elements > 0)
478 break;
480 if (k >= table->num_chunks)
481 return;
483 g_assert (table->chunks [k]->num_elements > 0);
484 next = table->chunks [k]->data [0];
485 } else
486 return;
488 g_assert ((gint8*)this->code_start + this->code_size <= (gint8*)next->code_start + next->code_size);
493 static MonoJitInfoTable*
494 jit_info_table_realloc (MonoJitInfoTable *old)
496 int i;
497 int num_elements = jit_info_table_num_elements (old);
498 int required_size;
499 int num_chunks;
500 int new_chunk, new_element;
501 MonoJitInfoTable *new;
503 /* number of needed places for elements needed */
504 required_size = (int)((long)num_elements * JIT_INFO_TABLE_FILL_RATIO_DENOM / JIT_INFO_TABLE_FILL_RATIO_NOM);
505 num_chunks = (required_size + MONO_JIT_INFO_TABLE_CHUNK_SIZE - 1) / MONO_JIT_INFO_TABLE_CHUNK_SIZE;
507 new = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*) * num_chunks);
508 new->domain = old->domain;
509 new->num_chunks = num_chunks;
511 for (i = 0; i < num_chunks; ++i)
512 new->chunks [i] = jit_info_table_new_chunk ();
514 new_chunk = 0;
515 new_element = 0;
516 for (i = 0; i < old->num_chunks; ++i) {
517 MonoJitInfoTableChunk *chunk = old->chunks [i];
518 int chunk_num_elements = chunk->num_elements;
519 int j;
521 for (j = 0; j < chunk_num_elements; ++j) {
522 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j])) {
523 g_assert (new_chunk < num_chunks);
524 new->chunks [new_chunk]->data [new_element] = chunk->data [j];
525 if (++new_element >= JIT_INFO_TABLE_FILLED_NUM_ELEMENTS) {
526 new->chunks [new_chunk]->num_elements = new_element;
527 ++new_chunk;
528 new_element = 0;
534 if (new_chunk < num_chunks) {
535 g_assert (new_chunk == num_chunks - 1);
536 new->chunks [new_chunk]->num_elements = new_element;
537 g_assert (new->chunks [new_chunk]->num_elements > 0);
540 for (i = 0; i < num_chunks; ++i) {
541 MonoJitInfoTableChunk *chunk = new->chunks [i];
542 MonoJitInfo *ji = chunk->data [chunk->num_elements - 1];
544 new->chunks [i]->last_code_end = (gint8*)ji->code_start + ji->code_size;
547 return new;
550 static void
551 jit_info_table_split_chunk (MonoJitInfoTableChunk *chunk, MonoJitInfoTableChunk **new1p, MonoJitInfoTableChunk **new2p)
553 MonoJitInfoTableChunk *new1 = jit_info_table_new_chunk ();
554 MonoJitInfoTableChunk *new2 = jit_info_table_new_chunk ();
556 g_assert (chunk->num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE);
558 new1->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE / 2;
559 new2->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE - new1->num_elements;
561 memcpy ((void*)new1->data, (void*)chunk->data, sizeof (MonoJitInfo*) * new1->num_elements);
562 memcpy ((void*)new2->data, (void*)(chunk->data + new1->num_elements), sizeof (MonoJitInfo*) * new2->num_elements);
564 new1->last_code_end = (gint8*)new1->data [new1->num_elements - 1]->code_start
565 + new1->data [new1->num_elements - 1]->code_size;
566 new2->last_code_end = (gint8*)new2->data [new2->num_elements - 1]->code_start
567 + new2->data [new2->num_elements - 1]->code_size;
569 *new1p = new1;
570 *new2p = new2;
573 static MonoJitInfoTable*
574 jit_info_table_copy_and_split_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
576 MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
577 + sizeof (MonoJitInfoTableChunk*) * (table->num_chunks + 1));
578 int i, j;
580 new_table->domain = table->domain;
581 new_table->num_chunks = table->num_chunks + 1;
583 j = 0;
584 for (i = 0; i < table->num_chunks; ++i) {
585 if (table->chunks [i] == chunk) {
586 jit_info_table_split_chunk (chunk, &new_table->chunks [j], &new_table->chunks [j + 1]);
587 j += 2;
588 } else {
589 new_table->chunks [j] = table->chunks [i];
590 ++new_table->chunks [j]->refcount;
591 ++j;
595 g_assert (j == new_table->num_chunks);
597 return new_table;
600 static MonoJitInfoTableChunk*
601 jit_info_table_purify_chunk (MonoJitInfoTableChunk *old)
603 MonoJitInfoTableChunk *new = jit_info_table_new_chunk ();
604 int i, j;
606 j = 0;
607 for (i = 0; i < old->num_elements; ++i) {
608 if (!IS_JIT_INFO_TOMBSTONE (old->data [i]))
609 new->data [j++] = old->data [i];
612 new->num_elements = j;
613 if (new->num_elements > 0)
614 new->last_code_end = (gint8*)new->data [j - 1]->code_start + new->data [j - 1]->code_size;
615 else
616 new->last_code_end = old->last_code_end;
618 return new;
621 static MonoJitInfoTable*
622 jit_info_table_copy_and_purify_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
624 MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
625 + sizeof (MonoJitInfoTableChunk*) * table->num_chunks);
626 int i, j;
628 new_table->domain = table->domain;
629 new_table->num_chunks = table->num_chunks;
631 j = 0;
632 for (i = 0; i < table->num_chunks; ++i) {
633 if (table->chunks [i] == chunk)
634 new_table->chunks [j++] = jit_info_table_purify_chunk (table->chunks [i]);
635 else {
636 new_table->chunks [j] = table->chunks [i];
637 ++new_table->chunks [j]->refcount;
638 ++j;
642 g_assert (j == new_table->num_chunks);
644 return new_table;
647 /* As we add an element to the table the case can arise that the chunk
648 * to which we need to add is already full. In that case we have to
649 * allocate a new table and do something about that chunk. We have
650 * several strategies:
652 * If the number of elements in the table is below the low watermark
653 * or above the high watermark, we reallocate the whole table.
654 * Otherwise we only concern ourselves with the overflowing chunk:
656 * If there are no tombstones in the chunk then we split the chunk in
657 * two, each half full.
659 * If the chunk does contain tombstones, we just make a new copy of
660 * the chunk without the tombstones, which will have room for at least
661 * the one element we have to add.
663 static MonoJitInfoTable*
664 jit_info_table_chunk_overflow (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
666 int num_elements = jit_info_table_num_elements (table);
667 int i;
669 if (num_elements < JIT_INFO_TABLE_LOW_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)
670 || num_elements > JIT_INFO_TABLE_HIGH_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)) {
671 //printf ("reallocing table\n");
672 return jit_info_table_realloc (table);
675 /* count the number of non-tombstone elements in the chunk */
676 num_elements = 0;
677 for (i = 0; i < chunk->num_elements; ++i) {
678 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [i]))
679 ++num_elements;
682 if (num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
683 //printf ("splitting chunk\n");
684 return jit_info_table_copy_and_split_chunk (table, chunk);
687 //printf ("purifying chunk\n");
688 return jit_info_table_copy_and_purify_chunk (table, chunk);
691 /* We add elements to the table by first making space for them by
692 * shifting the elements at the back to the right, one at a time.
693 * This results in duplicate entries during the process, but during
694 * all the time the table is in a sorted state. Also, when an element
695 * is replaced by another one, the element that replaces it has an end
696 * address that is equal to or lower than that of the replaced
697 * element. That property is necessary to guarantee that when
698 * searching for an element we end up at a position not higher than
699 * the one we're looking for (i.e. we either find the element directly
700 * or we end up to the left of it).
702 void
703 mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
705 MonoJitInfoTable *table;
706 int chunk_pos, pos;
707 MonoJitInfoTableChunk *chunk;
708 int num_elements;
709 int i;
711 g_assert (ji->method != NULL);
713 mono_domain_lock (domain);
715 ++mono_stats.jit_info_table_insert_count;
717 table = domain->jit_info_table;
719 restart:
720 chunk_pos = jit_info_table_index (table, (gint8*)ji->code_start + ji->code_size);
721 g_assert (chunk_pos < table->num_chunks);
722 chunk = table->chunks [chunk_pos];
724 if (chunk->num_elements >= MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
725 MonoJitInfoTable *new_table = jit_info_table_chunk_overflow (table, chunk);
727 /* Debugging code, should be removed. */
728 //jit_info_table_check (new_table);
730 domain->jit_info_table = new_table;
731 mono_memory_barrier ();
732 domain->num_jit_info_tables++;
733 mono_thread_hazardous_free_or_queue (table, (MonoHazardousFreeFunc)jit_info_table_free);
734 table = new_table;
736 goto restart;
739 /* Debugging code, should be removed. */
740 //jit_info_table_check (table);
742 num_elements = chunk->num_elements;
744 pos = jit_info_table_chunk_index (chunk, NULL, (gint8*)ji->code_start + ji->code_size);
746 /* First we need to size up the chunk by one, by copying the
747 last item, or inserting the first one, if the table is
748 empty. */
749 if (num_elements > 0)
750 chunk->data [num_elements] = chunk->data [num_elements - 1];
751 else
752 chunk->data [0] = ji;
753 mono_memory_write_barrier ();
754 chunk->num_elements = ++num_elements;
756 /* Shift the elements up one by one. */
757 for (i = num_elements - 2; i >= pos; --i) {
758 mono_memory_write_barrier ();
759 chunk->data [i + 1] = chunk->data [i];
762 /* Now we have room and can insert the new item. */
763 mono_memory_write_barrier ();
764 chunk->data [pos] = ji;
766 /* Set the high code end address chunk entry. */
767 chunk->last_code_end = (gint8*)chunk->data [chunk->num_elements - 1]->code_start
768 + chunk->data [chunk->num_elements - 1]->code_size;
770 /* Debugging code, should be removed. */
771 //jit_info_table_check (table);
773 mono_domain_unlock (domain);
776 static MonoJitInfo*
777 mono_jit_info_make_tombstone (MonoJitInfo *ji)
779 MonoJitInfo *tombstone = g_new0 (MonoJitInfo, 1);
781 tombstone->code_start = ji->code_start;
782 tombstone->code_size = ji->code_size;
783 tombstone->method = JIT_INFO_TOMBSTONE_MARKER;
785 return tombstone;
789 * LOCKING: domain lock
791 static void
792 mono_jit_info_free_or_queue (MonoDomain *domain, MonoJitInfo *ji)
794 if (domain->num_jit_info_tables <= 1) {
795 /* Can it actually happen that we only have one table
796 but ji is still hazardous? */
797 mono_thread_hazardous_free_or_queue (ji, g_free);
798 } else {
799 domain->jit_info_free_queue = g_slist_prepend (domain->jit_info_free_queue, ji);
803 void
804 mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
806 MonoJitInfoTable *table;
807 MonoJitInfoTableChunk *chunk;
808 gpointer start = ji->code_start;
809 int chunk_pos, pos;
811 mono_domain_lock (domain);
812 table = domain->jit_info_table;
814 ++mono_stats.jit_info_table_remove_count;
816 chunk_pos = jit_info_table_index (table, start);
817 g_assert (chunk_pos < table->num_chunks);
819 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], NULL, start);
821 do {
822 chunk = table->chunks [chunk_pos];
824 while (pos < chunk->num_elements) {
825 if (chunk->data [pos] == ji)
826 goto found;
828 g_assert (IS_JIT_INFO_TOMBSTONE (chunk->data [pos]));
829 g_assert ((guint8*)chunk->data [pos]->code_start + chunk->data [pos]->code_size
830 <= (guint8*)ji->code_start + ji->code_size);
832 ++pos;
835 ++chunk_pos;
836 pos = 0;
837 } while (chunk_pos < table->num_chunks);
839 found:
840 g_assert (chunk->data [pos] == ji);
842 chunk->data [pos] = mono_jit_info_make_tombstone (ji);
844 /* Debugging code, should be removed. */
845 //jit_info_table_check (table);
847 mono_jit_info_free_or_queue (domain, ji);
849 mono_domain_unlock (domain);
852 static MonoAotModuleInfoTable*
853 mono_aot_module_info_table_new (void)
855 return g_array_new (FALSE, FALSE, sizeof (gpointer));
858 static int
859 aot_info_table_index (MonoAotModuleInfoTable *table, char *addr)
861 int left = 0, right = table->len;
863 while (left < right) {
864 int pos = (left + right) / 2;
865 AotModuleInfo *ainfo = g_array_index (table, gpointer, pos);
866 char *start = ainfo->start;
867 char *end = ainfo->end;
869 if (addr < start)
870 right = pos;
871 else if (addr >= end)
872 left = pos + 1;
873 else
874 return pos;
877 return left;
880 void
881 mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
883 AotModuleInfo *ainfo = g_new0 (AotModuleInfo, 1);
884 int pos;
886 ainfo->image = image;
887 ainfo->start = start;
888 ainfo->end = end;
890 mono_appdomains_lock ();
892 if (!aot_modules)
893 aot_modules = mono_aot_module_info_table_new ();
895 pos = aot_info_table_index (aot_modules, start);
897 g_array_insert_val (aot_modules, pos, ainfo);
899 mono_appdomains_unlock ();
902 static MonoImage*
903 mono_jit_info_find_aot_module (guint8* addr)
905 guint left = 0, right;
907 if (!aot_modules)
908 return NULL;
910 mono_appdomains_lock ();
912 right = aot_modules->len;
913 while (left < right) {
914 guint pos = (left + right) / 2;
915 AotModuleInfo *ai = g_array_index (aot_modules, gpointer, pos);
917 if (addr < (guint8*)ai->start)
918 right = pos;
919 else if (addr >= (guint8*)ai->end)
920 left = pos + 1;
921 else {
922 mono_appdomains_unlock ();
923 return ai->image;
927 mono_appdomains_unlock ();
929 return NULL;
932 void
933 mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func)
935 jit_info_find_in_aot_func = func;
938 gpointer
939 mono_jit_info_get_code_start (MonoJitInfo* ji)
941 return ji->code_start;
945 mono_jit_info_get_code_size (MonoJitInfo* ji)
947 return ji->code_size;
950 MonoMethod*
951 mono_jit_info_get_method (MonoJitInfo* ji)
953 return ji->method;
956 static gpointer
957 jit_info_key_extract (gpointer value)
959 MonoJitInfo *info = (MonoJitInfo*)value;
961 return info->method;
964 static gpointer*
965 jit_info_next_value (gpointer value)
967 MonoJitInfo *info = (MonoJitInfo*)value;
969 return (gpointer*)&info->next_jit_code_hash;
972 void
973 mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
975 mono_internal_hash_table_init (jit_code_hash,
976 mono_aligned_addr_hash,
977 jit_info_key_extract,
978 jit_info_next_value);
981 MonoGenericJitInfo*
982 mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
984 if (ji->has_generic_jit_info)
985 return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
986 else
987 return NULL;
991 * mono_jit_info_get_generic_sharing_context:
992 * @ji: a jit info
994 * Returns the jit info's generic sharing context, or NULL if it
995 * doesn't have one.
997 MonoGenericSharingContext*
998 mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
1000 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
1002 if (gi)
1003 return gi->generic_sharing_context;
1004 else
1005 return NULL;
1009 * mono_jit_info_set_generic_sharing_context:
1010 * @ji: a jit info
1011 * @gsctx: a generic sharing context
1013 * Sets the jit info's generic sharing context. The jit info must
1014 * have memory allocated for the context.
1016 void
1017 mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
1019 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
1021 g_assert (gi);
1023 gi->generic_sharing_context = gsctx;
1026 void
1027 mono_install_create_domain_hook (MonoCreateDomainFunc func)
1029 create_domain_hook = func;
1032 void
1033 mono_install_free_domain_hook (MonoFreeDomainFunc func)
1035 free_domain_hook = func;
1039 * mono_string_equal:
1040 * @s1: First string to compare
1041 * @s2: Second string to compare
1043 * Returns FALSE if the strings differ.
1045 gboolean
1046 mono_string_equal (MonoString *s1, MonoString *s2)
1048 int l1 = mono_string_length (s1);
1049 int l2 = mono_string_length (s2);
1051 if (s1 == s2)
1052 return TRUE;
1053 if (l1 != l2)
1054 return FALSE;
1056 return memcmp (mono_string_chars (s1), mono_string_chars (s2), l1 * 2) == 0;
1060 * mono_string_hash:
1061 * @s: the string to hash
1063 * Returns the hash for the string.
1065 guint
1066 mono_string_hash (MonoString *s)
1068 const guint16 *p = mono_string_chars (s);
1069 int i, len = mono_string_length (s);
1070 guint h = 0;
1072 for (i = 0; i < len; i++) {
1073 h = (h << 5) - h + *p;
1074 p++;
1077 return h;
1080 static gboolean
1081 mono_ptrarray_equal (gpointer *s1, gpointer *s2)
1083 int len = GPOINTER_TO_INT (s1 [0]);
1084 if (len != GPOINTER_TO_INT (s2 [0]))
1085 return FALSE;
1087 return memcmp (s1 + 1, s2 + 1, len * sizeof(gpointer)) == 0;
1090 static guint
1091 mono_ptrarray_hash (gpointer *s)
1093 int i;
1094 int len = GPOINTER_TO_INT (s [0]);
1095 guint hash = 0;
1097 for (i = 1; i < len; i++)
1098 hash += GPOINTER_TO_UINT (s [i]);
1100 return hash;
1104 * Allocate an id for domain and set domain->domain_id.
1105 * LOCKING: must be called while holding appdomains_mutex.
1106 * We try to assign low numbers to the domain, so it can be used
1107 * as an index in data tables to lookup domain-specific info
1108 * with minimal memory overhead. We also try not to reuse the
1109 * same id too quickly (to help debugging).
1111 static int
1112 domain_id_alloc (MonoDomain *domain)
1114 int id = -1, i;
1115 if (!appdomains_list) {
1116 appdomain_list_size = 2;
1117 appdomains_list = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1119 for (i = appdomain_next; i < appdomain_list_size; ++i) {
1120 if (!appdomains_list [i]) {
1121 id = i;
1122 break;
1125 if (id == -1) {
1126 for (i = 0; i < appdomain_next; ++i) {
1127 if (!appdomains_list [i]) {
1128 id = i;
1129 break;
1133 if (id == -1) {
1134 MonoDomain **new_list;
1135 int new_size = appdomain_list_size * 2;
1136 if (new_size >= (1 << 16))
1137 g_assert_not_reached ();
1138 id = appdomain_list_size;
1139 new_list = mono_gc_alloc_fixed (new_size * sizeof (void*), NULL);
1140 memcpy (new_list, appdomains_list, appdomain_list_size * sizeof (void*));
1141 mono_gc_free_fixed (appdomains_list);
1142 appdomains_list = new_list;
1143 appdomain_list_size = new_size;
1145 domain->domain_id = id;
1146 appdomains_list [id] = domain;
1147 appdomain_next++;
1148 if (appdomain_next > appdomain_list_size)
1149 appdomain_next = 0;
1150 return id;
1153 static guint32 domain_gc_bitmap [sizeof(MonoDomain)/4/32 + 1];
1154 static gpointer domain_gc_desc = NULL;
1155 static guint32 domain_shadow_serial = 0L;
1157 MonoDomain *
1158 mono_domain_create (void)
1160 MonoDomain *domain;
1161 guint32 shadow_serial;
1163 mono_appdomains_lock ();
1164 shadow_serial = domain_shadow_serial++;
1166 if (!domain_gc_desc) {
1167 unsigned int i, bit = 0;
1168 for (i = G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_OBJECT); i < G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_GC_TRACKED); i += sizeof (gpointer)) {
1169 bit = i / sizeof (gpointer);
1170 domain_gc_bitmap [bit / 32] |= 1 << (bit % 32);
1172 domain_gc_desc = mono_gc_make_descr_from_bitmap ((gsize*)domain_gc_bitmap, bit + 1);
1174 mono_appdomains_unlock ();
1176 domain = mono_gc_alloc_fixed (sizeof (MonoDomain), domain_gc_desc);
1177 domain->shadow_serial = shadow_serial;
1178 domain->domain = NULL;
1179 domain->setup = NULL;
1180 domain->friendly_name = NULL;
1181 domain->search_path = NULL;
1183 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);
1185 mono_profiler_appdomain_event (domain, MONO_PROFILE_START_LOAD);
1187 domain->mp = mono_mempool_new ();
1188 domain->code_mp = mono_code_manager_new ();
1189 domain->env = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1190 domain->domain_assemblies = NULL;
1191 domain->class_vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1192 domain->proxy_vtable_hash = g_hash_table_new ((GHashFunc)mono_ptrarray_hash, (GCompareFunc)mono_ptrarray_equal);
1193 domain->static_data_array = NULL;
1194 mono_jit_code_hash_init (&domain->jit_code_hash);
1195 domain->ldstr_table = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1196 domain->num_jit_info_tables = 1;
1197 domain->jit_info_table = jit_info_table_new (domain);
1198 domain->jit_info_free_queue = NULL;
1199 domain->finalizable_objects_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1200 #ifndef HAVE_SGEN_GC
1201 domain->track_resurrection_handles_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1202 #endif
1204 InitializeCriticalSection (&domain->lock);
1205 InitializeCriticalSection (&domain->assemblies_lock);
1206 InitializeCriticalSection (&domain->jit_code_hash_lock);
1207 InitializeCriticalSection (&domain->finalizable_objects_hash_lock);
1209 domain->method_rgctx_hash = NULL;
1211 mono_appdomains_lock ();
1212 domain_id_alloc (domain);
1213 mono_appdomains_unlock ();
1215 mono_perfcounters->loader_appdomains++;
1216 mono_perfcounters->loader_total_appdomains++;
1218 mono_debug_domain_create (domain);
1220 if (create_domain_hook)
1221 create_domain_hook (domain);
1223 mono_profiler_appdomain_loaded (domain, MONO_PROFILE_OK);
1225 return domain;
1229 * mono_init_internal:
1231 * Creates the initial application domain and initializes the mono_defaults
1232 * structure.
1233 * This function is guaranteed to not run any IL code.
1234 * If exe_filename is not NULL, the method will determine the required runtime
1235 * from the exe configuration file or the version PE field.
1236 * If runtime_version is not NULL, that runtime version will be used.
1237 * Either exe_filename or runtime_version must be provided.
1239 * Returns: the initial domain.
1241 static MonoDomain *
1242 mono_init_internal (const char *filename, const char *exe_filename, const char *runtime_version)
1244 static MonoDomain *domain = NULL;
1245 MonoAssembly *ass = NULL;
1246 MonoImageOpenStatus status = MONO_IMAGE_OK;
1247 const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
1248 int n;
1250 if (domain)
1251 g_assert_not_reached ();
1253 #ifdef HOST_WIN32
1254 /* Avoid system error message boxes. */
1255 SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1257 mono_load_coree (exe_filename);
1258 #endif
1260 mono_perfcounters_init ();
1262 mono_counters_register ("Max native code in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_size);
1263 mono_counters_register ("Max code space allocated in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_alloc);
1264 mono_counters_register ("Total code space allocated", MONO_COUNTER_INT|MONO_COUNTER_JIT, &total_domain_code_alloc);
1266 mono_gc_base_init ();
1268 appdomain_thread_id = TlsAlloc ();
1270 InitializeCriticalSection (&appdomains_mutex);
1272 mono_metadata_init ();
1273 mono_images_init ();
1274 mono_assemblies_init ();
1275 mono_classes_init ();
1276 mono_loader_init ();
1277 mono_reflection_init ();
1279 /* FIXME: When should we release this memory? */
1280 MONO_GC_REGISTER_ROOT (appdomains_list);
1282 domain = mono_domain_create ();
1283 mono_root_domain = domain;
1285 SET_APPDOMAIN (domain);
1287 /* Get a list of runtimes supported by the exe */
1288 if (exe_filename != NULL) {
1290 * This function will load the exe file as a MonoImage. We need to close it, but
1291 * that would mean it would be reloaded later. So instead, we save it to
1292 * exe_image, and close it during shutdown.
1294 get_runtimes_from_exe (exe_filename, &exe_image, runtimes);
1295 #ifdef HOST_WIN32
1296 if (!exe_image) {
1297 exe_image = mono_assembly_open_from_bundle (exe_filename, NULL, FALSE);
1298 if (!exe_image)
1299 exe_image = mono_image_open (exe_filename, NULL);
1301 mono_fixup_exe_image (exe_image);
1302 #endif
1303 } else if (runtime_version != NULL) {
1304 runtimes [0] = get_runtime_by_version (runtime_version);
1305 runtimes [1] = NULL;
1308 if (runtimes [0] == NULL) {
1309 const MonoRuntimeInfo *default_runtime = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
1310 runtimes [0] = default_runtime;
1311 runtimes [1] = NULL;
1312 g_print ("WARNING: The runtime version supported by this application is unavailable.\n");
1313 g_print ("Using default runtime: %s\n", default_runtime->runtime_version);
1316 /* The selected runtime will be the first one for which there is a mscrolib.dll */
1317 for (n = 0; runtimes [n] != NULL && ass == NULL; n++) {
1318 current_runtime = runtimes [n];
1319 ass = mono_assembly_load_corlib (current_runtime, &status);
1320 if (status != MONO_IMAGE_OK && status != MONO_IMAGE_ERROR_ERRNO)
1321 break;
1325 /* Now that we have a runtime, set the policy for unhandled exceptions */
1326 if (mono_framework_version () < 2) {
1327 mono_runtime_unhandled_exception_policy_set (MONO_UNHANDLED_POLICY_LEGACY);
1330 if ((status != MONO_IMAGE_OK) || (ass == NULL)) {
1331 switch (status){
1332 case MONO_IMAGE_ERROR_ERRNO: {
1333 char *corlib_file = g_build_filename (mono_assembly_getrootdir (), "mono", current_runtime->framework_version, "mscorlib.dll", NULL);
1334 g_print ("The assembly mscorlib.dll was not found or could not be loaded.\n");
1335 g_print ("It should have been installed in the `%s' directory.\n", corlib_file);
1336 g_free (corlib_file);
1337 break;
1339 case MONO_IMAGE_IMAGE_INVALID:
1340 g_print ("The file %s/mscorlib.dll is an invalid CIL image\n",
1341 mono_assembly_getrootdir ());
1342 break;
1343 case MONO_IMAGE_MISSING_ASSEMBLYREF:
1344 g_print ("Missing assembly reference in %s/mscorlib.dll\n",
1345 mono_assembly_getrootdir ());
1346 break;
1347 case MONO_IMAGE_OK:
1348 /* to suppress compiler warning */
1349 break;
1352 exit (1);
1354 mono_defaults.corlib = mono_assembly_get_image (ass);
1356 mono_defaults.object_class = mono_class_from_name (
1357 mono_defaults.corlib, "System", "Object");
1358 g_assert (mono_defaults.object_class != 0);
1360 mono_defaults.void_class = mono_class_from_name (
1361 mono_defaults.corlib, "System", "Void");
1362 g_assert (mono_defaults.void_class != 0);
1364 mono_defaults.boolean_class = mono_class_from_name (
1365 mono_defaults.corlib, "System", "Boolean");
1366 g_assert (mono_defaults.boolean_class != 0);
1368 mono_defaults.byte_class = mono_class_from_name (
1369 mono_defaults.corlib, "System", "Byte");
1370 g_assert (mono_defaults.byte_class != 0);
1372 mono_defaults.sbyte_class = mono_class_from_name (
1373 mono_defaults.corlib, "System", "SByte");
1374 g_assert (mono_defaults.sbyte_class != 0);
1376 mono_defaults.int16_class = mono_class_from_name (
1377 mono_defaults.corlib, "System", "Int16");
1378 g_assert (mono_defaults.int16_class != 0);
1380 mono_defaults.uint16_class = mono_class_from_name (
1381 mono_defaults.corlib, "System", "UInt16");
1382 g_assert (mono_defaults.uint16_class != 0);
1384 mono_defaults.int32_class = mono_class_from_name (
1385 mono_defaults.corlib, "System", "Int32");
1386 g_assert (mono_defaults.int32_class != 0);
1388 mono_defaults.uint32_class = mono_class_from_name (
1389 mono_defaults.corlib, "System", "UInt32");
1390 g_assert (mono_defaults.uint32_class != 0);
1392 mono_defaults.uint_class = mono_class_from_name (
1393 mono_defaults.corlib, "System", "UIntPtr");
1394 g_assert (mono_defaults.uint_class != 0);
1396 mono_defaults.int_class = mono_class_from_name (
1397 mono_defaults.corlib, "System", "IntPtr");
1398 g_assert (mono_defaults.int_class != 0);
1400 mono_defaults.int64_class = mono_class_from_name (
1401 mono_defaults.corlib, "System", "Int64");
1402 g_assert (mono_defaults.int64_class != 0);
1404 mono_defaults.uint64_class = mono_class_from_name (
1405 mono_defaults.corlib, "System", "UInt64");
1406 g_assert (mono_defaults.uint64_class != 0);
1408 mono_defaults.single_class = mono_class_from_name (
1409 mono_defaults.corlib, "System", "Single");
1410 g_assert (mono_defaults.single_class != 0);
1412 mono_defaults.double_class = mono_class_from_name (
1413 mono_defaults.corlib, "System", "Double");
1414 g_assert (mono_defaults.double_class != 0);
1416 mono_defaults.char_class = mono_class_from_name (
1417 mono_defaults.corlib, "System", "Char");
1418 g_assert (mono_defaults.char_class != 0);
1420 mono_defaults.string_class = mono_class_from_name (
1421 mono_defaults.corlib, "System", "String");
1422 g_assert (mono_defaults.string_class != 0);
1424 mono_defaults.enum_class = mono_class_from_name (
1425 mono_defaults.corlib, "System", "Enum");
1426 g_assert (mono_defaults.enum_class != 0);
1428 mono_defaults.array_class = mono_class_from_name (
1429 mono_defaults.corlib, "System", "Array");
1430 g_assert (mono_defaults.array_class != 0);
1432 mono_defaults.delegate_class = mono_class_from_name (
1433 mono_defaults.corlib, "System", "Delegate");
1434 g_assert (mono_defaults.delegate_class != 0 );
1436 mono_defaults.multicastdelegate_class = mono_class_from_name (
1437 mono_defaults.corlib, "System", "MulticastDelegate");
1438 g_assert (mono_defaults.multicastdelegate_class != 0 );
1440 mono_defaults.asyncresult_class = mono_class_from_name (
1441 mono_defaults.corlib, "System.Runtime.Remoting.Messaging",
1442 "AsyncResult");
1443 g_assert (mono_defaults.asyncresult_class != 0 );
1445 mono_defaults.manualresetevent_class = mono_class_from_name (
1446 mono_defaults.corlib, "System.Threading", "ManualResetEvent");
1447 g_assert (mono_defaults.manualresetevent_class != 0 );
1449 mono_defaults.typehandle_class = mono_class_from_name (
1450 mono_defaults.corlib, "System", "RuntimeTypeHandle");
1451 g_assert (mono_defaults.typehandle_class != 0);
1453 mono_defaults.methodhandle_class = mono_class_from_name (
1454 mono_defaults.corlib, "System", "RuntimeMethodHandle");
1455 g_assert (mono_defaults.methodhandle_class != 0);
1457 mono_defaults.fieldhandle_class = mono_class_from_name (
1458 mono_defaults.corlib, "System", "RuntimeFieldHandle");
1459 g_assert (mono_defaults.fieldhandle_class != 0);
1461 mono_defaults.systemtype_class = mono_class_from_name (
1462 mono_defaults.corlib, "System", "Type");
1463 g_assert (mono_defaults.systemtype_class != 0);
1465 mono_defaults.monotype_class = mono_class_from_name (
1466 mono_defaults.corlib, "System", "MonoType");
1467 g_assert (mono_defaults.monotype_class != 0);
1469 mono_defaults.exception_class = mono_class_from_name (
1470 mono_defaults.corlib, "System", "Exception");
1471 g_assert (mono_defaults.exception_class != 0);
1473 mono_defaults.threadabortexception_class = mono_class_from_name (
1474 mono_defaults.corlib, "System.Threading", "ThreadAbortException");
1475 g_assert (mono_defaults.threadabortexception_class != 0);
1477 mono_defaults.thread_class = mono_class_from_name (
1478 mono_defaults.corlib, "System.Threading", "Thread");
1479 g_assert (mono_defaults.thread_class != 0);
1481 mono_defaults.internal_thread_class = mono_class_from_name (
1482 mono_defaults.corlib, "System.Threading", "InternalThread");
1483 if (!mono_defaults.internal_thread_class) {
1484 /* This can happen with an old mscorlib */
1485 fprintf (stderr, "Corlib too old for this runtime.\n");
1486 fprintf (stderr, "Loaded from: %s\n",
1487 mono_defaults.corlib? mono_image_get_filename (mono_defaults.corlib): "unknown");
1488 exit (1);
1491 mono_defaults.appdomain_class = mono_class_from_name (
1492 mono_defaults.corlib, "System", "AppDomain");
1493 g_assert (mono_defaults.appdomain_class != 0);
1495 mono_defaults.transparent_proxy_class = mono_class_from_name (
1496 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "TransparentProxy");
1497 g_assert (mono_defaults.transparent_proxy_class != 0);
1499 mono_defaults.real_proxy_class = mono_class_from_name (
1500 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "RealProxy");
1501 g_assert (mono_defaults.real_proxy_class != 0);
1503 mono_defaults.mono_method_message_class = mono_class_from_name (
1504 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", "MonoMethodMessage");
1505 g_assert (mono_defaults.mono_method_message_class != 0);
1507 mono_defaults.field_info_class = mono_class_from_name (
1508 mono_defaults.corlib, "System.Reflection", "FieldInfo");
1509 g_assert (mono_defaults.field_info_class != 0);
1511 mono_defaults.method_info_class = mono_class_from_name (
1512 mono_defaults.corlib, "System.Reflection", "MethodInfo");
1513 g_assert (mono_defaults.method_info_class != 0);
1515 mono_defaults.stringbuilder_class = mono_class_from_name (
1516 mono_defaults.corlib, "System.Text", "StringBuilder");
1517 g_assert (mono_defaults.stringbuilder_class != 0);
1519 mono_defaults.math_class = mono_class_from_name (
1520 mono_defaults.corlib, "System", "Math");
1521 g_assert (mono_defaults.math_class != 0);
1523 mono_defaults.stack_frame_class = mono_class_from_name (
1524 mono_defaults.corlib, "System.Diagnostics", "StackFrame");
1525 g_assert (mono_defaults.stack_frame_class != 0);
1527 mono_defaults.stack_trace_class = mono_class_from_name (
1528 mono_defaults.corlib, "System.Diagnostics", "StackTrace");
1529 g_assert (mono_defaults.stack_trace_class != 0);
1531 mono_defaults.marshal_class = mono_class_from_name (
1532 mono_defaults.corlib, "System.Runtime.InteropServices", "Marshal");
1533 g_assert (mono_defaults.marshal_class != 0);
1535 mono_defaults.iserializeable_class = mono_class_from_name (
1536 mono_defaults.corlib, "System.Runtime.Serialization", "ISerializable");
1537 g_assert (mono_defaults.iserializeable_class != 0);
1539 mono_defaults.serializationinfo_class = mono_class_from_name (
1540 mono_defaults.corlib, "System.Runtime.Serialization", "SerializationInfo");
1541 g_assert (mono_defaults.serializationinfo_class != 0);
1543 mono_defaults.streamingcontext_class = mono_class_from_name (
1544 mono_defaults.corlib, "System.Runtime.Serialization", "StreamingContext");
1545 g_assert (mono_defaults.streamingcontext_class != 0);
1547 mono_defaults.typed_reference_class = mono_class_from_name (
1548 mono_defaults.corlib, "System", "TypedReference");
1549 g_assert (mono_defaults.typed_reference_class != 0);
1551 mono_defaults.argumenthandle_class = mono_class_from_name (
1552 mono_defaults.corlib, "System", "RuntimeArgumentHandle");
1553 g_assert (mono_defaults.argumenthandle_class != 0);
1555 mono_defaults.marshalbyrefobject_class = mono_class_from_name (
1556 mono_defaults.corlib, "System", "MarshalByRefObject");
1557 g_assert (mono_defaults.marshalbyrefobject_class != 0);
1559 mono_defaults.monitor_class = mono_class_from_name (
1560 mono_defaults.corlib, "System.Threading", "Monitor");
1561 g_assert (mono_defaults.monitor_class != 0);
1563 mono_defaults.iremotingtypeinfo_class = mono_class_from_name (
1564 mono_defaults.corlib, "System.Runtime.Remoting", "IRemotingTypeInfo");
1565 g_assert (mono_defaults.iremotingtypeinfo_class != 0);
1567 mono_defaults.runtimesecurityframe_class = mono_class_from_name (
1568 mono_defaults.corlib, "System.Security", "RuntimeSecurityFrame");
1570 mono_defaults.executioncontext_class = mono_class_from_name (
1571 mono_defaults.corlib, "System.Threading", "ExecutionContext");
1573 mono_defaults.internals_visible_class = mono_class_from_name (
1574 mono_defaults.corlib, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute");
1576 mono_defaults.critical_finalizer_object = mono_class_from_name (
1577 mono_defaults.corlib, "System.Runtime.ConstrainedExecution", "CriticalFinalizerObject");
1580 * mscorlib needs a little help, only now it can load its friends list (after we have
1581 * loaded the InternalsVisibleToAttribute), load it now
1583 mono_assembly_load_friends (ass);
1585 mono_defaults.safehandle_class = mono_class_from_name (
1586 mono_defaults.corlib, "System.Runtime.InteropServices", "SafeHandle");
1588 mono_defaults.handleref_class = mono_class_from_name (
1589 mono_defaults.corlib, "System.Runtime.InteropServices", "HandleRef");
1591 mono_defaults.attribute_class = mono_class_from_name (
1592 mono_defaults.corlib, "System", "Attribute");
1594 mono_defaults.customattribute_data_class = mono_class_from_name (
1595 mono_defaults.corlib, "System.Reflection", "CustomAttributeData");
1597 /* these are initialized lazily when COM features are used */
1598 mono_defaults.variant_class = NULL;
1599 mono_defaults.com_object_class = NULL;
1600 mono_defaults.com_interop_proxy_class = NULL;
1601 mono_defaults.iunknown_class = NULL;
1602 mono_defaults.idispatch_class = NULL;
1605 * Note that mono_defaults.generic_*_class is only non-NULL if we're
1606 * using the 2.0 corlib.
1608 mono_class_init (mono_defaults.array_class);
1609 mono_defaults.generic_nullable_class = mono_class_from_name (
1610 mono_defaults.corlib, "System", "Nullable`1");
1611 mono_defaults.generic_ilist_class = mono_class_from_name (
1612 mono_defaults.corlib, "System.Collections.Generic", "IList`1");
1614 domain->friendly_name = g_path_get_basename (filename);
1616 _mono_debug_init_corlib (domain);
1618 return domain;
1622 * mono_init:
1624 * Creates the initial application domain and initializes the mono_defaults
1625 * structure.
1626 * This function is guaranteed to not run any IL code.
1627 * The runtime is initialized using the default runtime version.
1629 * Returns: the initial domain.
1631 MonoDomain *
1632 mono_init (const char *domain_name)
1634 return mono_init_internal (domain_name, NULL, DEFAULT_RUNTIME_VERSION);
1638 * mono_init_from_assembly:
1640 * Creates the initial application domain and initializes the mono_defaults
1641 * structure.
1642 * This function is guaranteed to not run any IL code.
1643 * The runtime is initialized using the runtime version required by the
1644 * provided executable. The version is determined by looking at the exe
1645 * configuration file and the version PE field)
1647 * Returns: the initial domain.
1649 MonoDomain *
1650 mono_init_from_assembly (const char *domain_name, const char *filename)
1652 return mono_init_internal (domain_name, filename, NULL);
1656 * mono_init_version:
1658 * Creates the initial application domain and initializes the mono_defaults
1659 * structure.
1660 * This function is guaranteed to not run any IL code.
1661 * The runtime is initialized using the provided rutime version.
1663 * Returns: the initial domain.
1665 MonoDomain *
1666 mono_init_version (const char *domain_name, const char *version)
1668 return mono_init_internal (domain_name, NULL, version);
1672 * mono_init_com_types:
1674 * Initializes all types needed for COM Interop in mono_defaults structure.
1676 void
1677 mono_init_com_types (void)
1679 static gboolean initialized = FALSE;
1681 if (initialized)
1682 return;
1684 /* FIXME: do I need some threading protection here */
1686 g_assert (mono_defaults.corlib);
1688 mono_defaults.variant_class = mono_class_from_name (
1689 mono_defaults.corlib, "System", "Variant");
1690 g_assert (mono_defaults.variant_class != 0);
1692 mono_defaults.com_object_class = mono_class_from_name (
1693 mono_defaults.corlib, "System", "__ComObject");
1694 g_assert (mono_defaults.com_object_class != 0);
1696 mono_defaults.com_interop_proxy_class = mono_class_from_name (
1697 mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
1698 g_assert (mono_defaults.com_interop_proxy_class != 0);
1700 mono_defaults.iunknown_class = mono_class_from_name (
1701 mono_defaults.corlib, "Mono.Interop", "IUnknown");
1702 g_assert (mono_defaults.iunknown_class != 0);
1704 mono_defaults.idispatch_class = mono_class_from_name (
1705 mono_defaults.corlib, "Mono.Interop", "IDispatch");
1706 g_assert (mono_defaults.idispatch_class != 0);
1708 initialized = TRUE;
1712 * mono_cleanup:
1714 * Cleans up all metadata modules.
1716 void
1717 mono_cleanup (void)
1719 mono_close_exe_image ();
1721 mono_loader_cleanup ();
1722 mono_classes_cleanup ();
1723 mono_assemblies_cleanup ();
1724 mono_images_cleanup ();
1725 mono_debug_cleanup ();
1726 mono_metadata_cleanup ();
1728 TlsFree (appdomain_thread_id);
1729 DeleteCriticalSection (&appdomains_mutex);
1732 void
1733 mono_close_exe_image (void)
1735 if (exe_image)
1736 mono_image_close (exe_image);
1740 * mono_get_root_domain:
1742 * The root AppDomain is the initial domain created by the runtime when it is
1743 * initialized. Programs execute on this AppDomain, but can create new ones
1744 * later. Currently there is no unmanaged API to create new AppDomains, this
1745 * must be done from managed code.
1747 * Returns: the root appdomain, to obtain the current domain, use mono_domain_get ()
1749 MonoDomain*
1750 mono_get_root_domain (void)
1752 return mono_root_domain;
1756 * mono_domain_get:
1758 * Returns: the current domain, to obtain the root domain use
1759 * mono_get_root_domain().
1761 MonoDomain *
1762 mono_domain_get ()
1764 return GET_APPDOMAIN ();
1767 void
1768 mono_domain_unset (void)
1770 SET_APPDOMAIN (NULL);
1773 void
1774 mono_domain_set_internal_with_options (MonoDomain *domain, gboolean migrate_exception)
1776 MonoInternalThread *thread;
1778 if (mono_domain_get () == domain)
1779 return;
1781 SET_APPDOMAIN (domain);
1782 SET_APPCONTEXT (domain->default_context);
1784 if (migrate_exception) {
1785 thread = mono_thread_internal_current ();
1786 if (!thread->abort_exc)
1787 return;
1789 g_assert (thread->abort_exc->object.vtable->domain != domain);
1790 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
1791 g_assert (thread->abort_exc->object.vtable->domain == domain);
1796 * mono_domain_set_internal:
1797 * @domain: the new domain
1799 * Sets the current domain to @domain.
1801 void
1802 mono_domain_set_internal (MonoDomain *domain)
1804 mono_domain_set_internal_with_options (domain, TRUE);
1807 void
1808 mono_domain_foreach (MonoDomainFunc func, gpointer user_data)
1810 int i, size;
1811 MonoDomain **copy;
1814 * Create a copy of the data to avoid calling the user callback
1815 * inside the lock because that could lead to deadlocks.
1816 * We can do this because this function is not perf. critical.
1818 mono_appdomains_lock ();
1819 size = appdomain_list_size;
1820 copy = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1821 memcpy (copy, appdomains_list, appdomain_list_size * sizeof (void*));
1822 mono_appdomains_unlock ();
1824 for (i = 0; i < size; ++i) {
1825 if (copy [i])
1826 func (copy [i], user_data);
1829 mono_gc_free_fixed (copy);
1833 * mono_domain_assembly_open:
1834 * @domain: the application domain
1835 * @name: file name of the assembly
1837 * fixme: maybe we should integrate this with mono_assembly_open ??
1839 MonoAssembly *
1840 mono_domain_assembly_open (MonoDomain *domain, const char *name)
1842 MonoDomain *current;
1843 MonoAssembly *ass;
1844 GSList *tmp;
1846 mono_domain_assemblies_lock (domain);
1847 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1848 ass = tmp->data;
1849 if (strcmp (name, ass->aname.name) == 0) {
1850 mono_domain_assemblies_unlock (domain);
1851 return ass;
1854 mono_domain_assemblies_unlock (domain);
1856 if (domain != mono_domain_get ()) {
1857 current = mono_domain_get ();
1859 mono_domain_set (domain, FALSE);
1860 ass = mono_assembly_open (name, NULL);
1861 mono_domain_set (current, FALSE);
1862 } else {
1863 ass = mono_assembly_open (name, NULL);
1866 return ass;
1869 static void
1870 free_slist (gpointer key, gpointer value, gpointer user_data)
1872 g_slist_free (value);
1875 #if HAVE_SGEN_GC
1876 static void
1877 unregister_vtable_reflection_type (gpointer key, gpointer value, gpointer user_data)
1879 MonoVTable *vtable = value;
1880 MonoObject *type = vtable->type;
1882 if (type->vtable->klass != mono_defaults.monotype_class)
1883 mono_gc_deregister_root ((char*)&vtable->type);
1885 #endif
1887 void
1888 mono_domain_free (MonoDomain *domain, gboolean force)
1890 int code_size, code_alloc;
1891 GSList *tmp;
1892 if ((domain == mono_root_domain) && !force) {
1893 g_warning ("cant unload root domain");
1894 return;
1897 if (mono_dont_free_domains)
1898 return;
1900 mono_profiler_appdomain_event (domain, MONO_PROFILE_START_UNLOAD);
1902 mono_debug_domain_unload (domain);
1904 mono_appdomains_lock ();
1905 appdomains_list [domain->domain_id] = NULL;
1906 mono_appdomains_unlock ();
1908 /* must do this early as it accesses fields and types */
1909 if (domain->special_static_fields) {
1910 mono_alloc_special_static_data_free (domain->special_static_fields);
1911 g_hash_table_destroy (domain->special_static_fields);
1912 domain->special_static_fields = NULL;
1916 * We must destroy all these hash tables here because they
1917 * contain references to managed objects belonging to the
1918 * domain. Once we let the GC clear the domain there must be
1919 * no more such references, or we'll crash if a collection
1920 * occurs.
1922 mono_g_hash_table_destroy (domain->ldstr_table);
1923 domain->ldstr_table = NULL;
1925 mono_g_hash_table_destroy (domain->env);
1926 domain->env = NULL;
1928 mono_reflection_cleanup_domain (domain);
1930 if (domain->type_hash) {
1931 mono_g_hash_table_destroy (domain->type_hash);
1932 domain->type_hash = NULL;
1934 if (domain->type_init_exception_hash) {
1935 mono_g_hash_table_destroy (domain->type_init_exception_hash);
1936 domain->type_init_exception_hash = NULL;
1939 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1940 MonoAssembly *ass = tmp->data;
1941 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);
1942 if (!mono_assembly_close_except_image_pools (ass))
1943 tmp->data = NULL;
1946 #if HAVE_SGEN_GC
1947 if (domain->class_vtable_hash)
1948 g_hash_table_foreach (domain->class_vtable_hash, unregister_vtable_reflection_type, NULL);
1949 #endif
1951 mono_gc_clear_domain (domain);
1953 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1954 MonoAssembly *ass = tmp->data;
1955 if (ass)
1956 mono_assembly_close_finish (ass);
1958 g_slist_free (domain->domain_assemblies);
1959 domain->domain_assemblies = NULL;
1962 * Send this after the assemblies have been unloaded and the domain is still in a
1963 * usable state.
1965 mono_profiler_appdomain_event (domain, MONO_PROFILE_END_UNLOAD);
1967 if (free_domain_hook)
1968 free_domain_hook (domain);
1970 /* FIXME: free delegate_hash_table when it's used */
1971 if (domain->search_path) {
1972 g_strfreev (domain->search_path);
1973 domain->search_path = NULL;
1975 domain->create_proxy_for_type_method = NULL;
1976 domain->private_invoke_method = NULL;
1977 domain->default_context = NULL;
1978 domain->out_of_memory_ex = NULL;
1979 domain->null_reference_ex = NULL;
1980 domain->stack_overflow_ex = NULL;
1981 domain->entry_assembly = NULL;
1983 g_free (domain->friendly_name);
1984 domain->friendly_name = NULL;
1985 g_hash_table_destroy (domain->class_vtable_hash);
1986 domain->class_vtable_hash = NULL;
1987 g_hash_table_destroy (domain->proxy_vtable_hash);
1988 domain->proxy_vtable_hash = NULL;
1989 if (domain->static_data_array) {
1990 mono_gc_free_fixed (domain->static_data_array);
1991 domain->static_data_array = NULL;
1993 mono_internal_hash_table_destroy (&domain->jit_code_hash);
1996 * There might still be jit info tables of this domain which
1997 * are not freed. Since the domain cannot be in use anymore,
1998 * this will free them.
2000 mono_thread_hazardous_try_free_all ();
2001 g_assert (domain->num_jit_info_tables == 1);
2002 jit_info_table_free (domain->jit_info_table);
2003 domain->jit_info_table = NULL;
2004 g_assert (!domain->jit_info_free_queue);
2006 /* collect statistics */
2007 code_alloc = mono_code_manager_size (domain->code_mp, &code_size);
2008 total_domain_code_alloc += code_alloc;
2009 max_domain_code_alloc = MAX (max_domain_code_alloc, code_alloc);
2010 max_domain_code_size = MAX (max_domain_code_size, code_size);
2012 #ifdef DEBUG_DOMAIN_UNLOAD
2013 mono_mempool_invalidate (domain->mp);
2014 mono_code_manager_invalidate (domain->code_mp);
2015 #else
2016 mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (domain->mp);
2017 mono_mempool_destroy (domain->mp);
2018 domain->mp = NULL;
2019 mono_code_manager_destroy (domain->code_mp);
2020 domain->code_mp = NULL;
2021 #endif
2023 g_hash_table_destroy (domain->finalizable_objects_hash);
2024 domain->finalizable_objects_hash = NULL;
2025 #ifndef HAVE_SGEN_GC
2026 if (domain->track_resurrection_objects_hash) {
2027 g_hash_table_foreach (domain->track_resurrection_objects_hash, free_slist, NULL);
2028 g_hash_table_destroy (domain->track_resurrection_objects_hash);
2030 if (domain->track_resurrection_handles_hash)
2031 g_hash_table_destroy (domain->track_resurrection_handles_hash);
2032 #endif
2033 if (domain->method_rgctx_hash) {
2034 g_hash_table_destroy (domain->method_rgctx_hash);
2035 domain->method_rgctx_hash = NULL;
2037 if (domain->generic_virtual_cases) {
2038 g_hash_table_destroy (domain->generic_virtual_cases);
2039 domain->generic_virtual_cases = NULL;
2042 DeleteCriticalSection (&domain->finalizable_objects_hash_lock);
2043 DeleteCriticalSection (&domain->assemblies_lock);
2044 DeleteCriticalSection (&domain->jit_code_hash_lock);
2045 DeleteCriticalSection (&domain->lock);
2046 domain->setup = NULL;
2048 mono_gc_deregister_root ((char*)&(domain->MONO_DOMAIN_FIRST_GC_TRACKED));
2050 /* FIXME: anything else required ? */
2052 mono_gc_free_fixed (domain);
2054 mono_perfcounters->loader_appdomains--;
2056 if ((domain == mono_root_domain))
2057 mono_root_domain = NULL;
2061 * mono_domain_get_id:
2062 * @domainid: the ID
2064 * Returns: the a domain for a specific domain id.
2066 MonoDomain *
2067 mono_domain_get_by_id (gint32 domainid)
2069 MonoDomain * domain;
2071 mono_appdomains_lock ();
2072 if (domainid < appdomain_list_size)
2073 domain = appdomains_list [domainid];
2074 else
2075 domain = NULL;
2076 mono_appdomains_unlock ();
2078 return domain;
2081 gint32
2082 mono_domain_get_id (MonoDomain *domain)
2084 return domain->domain_id;
2088 * mono_domain_alloc:
2090 * LOCKING: Acquires the domain lock.
2092 gpointer
2093 mono_domain_alloc (MonoDomain *domain, guint size)
2095 gpointer res;
2097 mono_domain_lock (domain);
2098 mono_perfcounters->loader_bytes += size;
2099 res = mono_mempool_alloc (domain->mp, size);
2100 mono_domain_unlock (domain);
2102 return res;
2106 * mono_domain_alloc0:
2108 * LOCKING: Acquires the domain lock.
2110 gpointer
2111 mono_domain_alloc0 (MonoDomain *domain, guint size)
2113 gpointer res;
2115 mono_domain_lock (domain);
2116 mono_perfcounters->loader_bytes += size;
2117 res = mono_mempool_alloc0 (domain->mp, size);
2118 mono_domain_unlock (domain);
2120 return res;
2124 * mono_domain_code_reserve:
2126 * LOCKING: Acquires the domain lock.
2128 void*
2129 mono_domain_code_reserve (MonoDomain *domain, int size)
2131 gpointer res;
2133 mono_domain_lock (domain);
2134 res = mono_code_manager_reserve (domain->code_mp, size);
2135 mono_domain_unlock (domain);
2137 return res;
2141 * mono_domain_code_reserve_align:
2143 * LOCKING: Acquires the domain lock.
2145 void*
2146 mono_domain_code_reserve_align (MonoDomain *domain, int size, int alignment)
2148 gpointer res;
2150 mono_domain_lock (domain);
2151 res = mono_code_manager_reserve_align (domain->code_mp, size, alignment);
2152 mono_domain_unlock (domain);
2154 return res;
2158 * mono_domain_code_commit:
2160 * LOCKING: Acquires the domain lock.
2162 void
2163 mono_domain_code_commit (MonoDomain *domain, void *data, int size, int newsize)
2165 mono_domain_lock (domain);
2166 mono_code_manager_commit (domain->code_mp, data, size, newsize);
2167 mono_domain_unlock (domain);
2171 * mono_domain_code_foreach:
2172 * Iterate over the code thunks of the code manager of @domain.
2174 * The @func callback MUST not take any locks. If it really needs to, it must respect
2175 * the locking rules of the runtime: http://www.mono-project.com/Mono:Runtime:Documentation:ThreadSafety
2176 * LOCKING: Acquires the domain lock.
2179 void
2180 mono_domain_code_foreach (MonoDomain *domain, MonoCodeManagerFunc func, void *user_data)
2182 mono_domain_lock (domain);
2183 mono_code_manager_foreach (domain->code_mp, func, user_data);
2184 mono_domain_unlock (domain);
2188 void
2189 mono_context_set (MonoAppContext * new_context)
2191 SET_APPCONTEXT (new_context);
2194 MonoAppContext *
2195 mono_context_get (void)
2197 return GET_APPCONTEXT ();
2200 /* LOCKING: the caller holds the lock for this domain */
2201 void
2202 mono_domain_add_class_static_data (MonoDomain *domain, MonoClass *klass, gpointer data, guint32 *bitmap)
2204 /* The first entry in the array is the index of the next free slot
2205 * and the total size of the array
2207 int next;
2208 if (domain->static_data_array) {
2209 int size = GPOINTER_TO_INT (domain->static_data_array [1]);
2210 next = GPOINTER_TO_INT (domain->static_data_array [0]);
2211 if (next >= size) {
2212 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * (size * 2), NULL);
2213 memcpy (new_array, domain->static_data_array, sizeof (gpointer) * size);
2214 size *= 2;
2215 new_array [1] = GINT_TO_POINTER (size);
2216 mono_gc_free_fixed (domain->static_data_array);
2217 domain->static_data_array = new_array;
2219 } else {
2220 int size = 32;
2221 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * size, NULL);
2222 next = 2;
2223 new_array [0] = GINT_TO_POINTER (next);
2224 new_array [1] = GINT_TO_POINTER (size);
2225 domain->static_data_array = new_array;
2227 domain->static_data_array [next++] = data;
2228 domain->static_data_array [0] = GINT_TO_POINTER (next);
2231 MonoImage*
2232 mono_get_corlib (void)
2234 return mono_defaults.corlib;
2237 MonoClass*
2238 mono_get_object_class (void)
2240 return mono_defaults.object_class;
2243 MonoClass*
2244 mono_get_byte_class (void)
2246 return mono_defaults.byte_class;
2249 MonoClass*
2250 mono_get_void_class (void)
2252 return mono_defaults.void_class;
2255 MonoClass*
2256 mono_get_boolean_class (void)
2258 return mono_defaults.boolean_class;
2261 MonoClass*
2262 mono_get_sbyte_class (void)
2264 return mono_defaults.sbyte_class;
2267 MonoClass*
2268 mono_get_int16_class (void)
2270 return mono_defaults.int16_class;
2273 MonoClass*
2274 mono_get_uint16_class (void)
2276 return mono_defaults.uint16_class;
2279 MonoClass*
2280 mono_get_int32_class (void)
2282 return mono_defaults.int32_class;
2285 MonoClass*
2286 mono_get_uint32_class (void)
2288 return mono_defaults.uint32_class;
2291 MonoClass*
2292 mono_get_intptr_class (void)
2294 return mono_defaults.int_class;
2297 MonoClass*
2298 mono_get_uintptr_class (void)
2300 return mono_defaults.uint_class;
2303 MonoClass*
2304 mono_get_int64_class (void)
2306 return mono_defaults.int64_class;
2309 MonoClass*
2310 mono_get_uint64_class (void)
2312 return mono_defaults.uint64_class;
2315 MonoClass*
2316 mono_get_single_class (void)
2318 return mono_defaults.single_class;
2321 MonoClass*
2322 mono_get_double_class (void)
2324 return mono_defaults.double_class;
2327 MonoClass*
2328 mono_get_char_class (void)
2330 return mono_defaults.char_class;
2333 MonoClass*
2334 mono_get_string_class (void)
2336 return mono_defaults.string_class;
2339 MonoClass*
2340 mono_get_enum_class (void)
2342 return mono_defaults.enum_class;
2345 MonoClass*
2346 mono_get_array_class (void)
2348 return mono_defaults.array_class;
2351 MonoClass*
2352 mono_get_thread_class (void)
2354 return mono_defaults.thread_class;
2357 MonoClass*
2358 mono_get_exception_class (void)
2360 return mono_defaults.exception_class;
2364 static char* get_attribute_value (const gchar **attribute_names,
2365 const gchar **attribute_values,
2366 const char *att_name)
2368 int n;
2369 for (n=0; attribute_names[n] != NULL; n++) {
2370 if (strcmp (attribute_names[n], att_name) == 0)
2371 return g_strdup (attribute_values[n]);
2373 return NULL;
2376 static void start_element (GMarkupParseContext *context,
2377 const gchar *element_name,
2378 const gchar **attribute_names,
2379 const gchar **attribute_values,
2380 gpointer user_data,
2381 GError **error)
2383 AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2385 if (strcmp (element_name, "configuration") == 0) {
2386 app_config->configuration_count++;
2387 return;
2389 if (strcmp (element_name, "startup") == 0) {
2390 app_config->startup_count++;
2391 return;
2394 if (app_config->configuration_count != 1 || app_config->startup_count != 1)
2395 return;
2397 if (strcmp (element_name, "requiredRuntime") == 0) {
2398 app_config->required_runtime = get_attribute_value (attribute_names, attribute_values, "version");
2399 } else if (strcmp (element_name, "supportedRuntime") == 0) {
2400 char *version = get_attribute_value (attribute_names, attribute_values, "version");
2401 app_config->supported_runtimes = g_slist_append (app_config->supported_runtimes, version);
2405 static void end_element (GMarkupParseContext *context,
2406 const gchar *element_name,
2407 gpointer user_data,
2408 GError **error)
2410 AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2412 if (strcmp (element_name, "configuration") == 0) {
2413 app_config->configuration_count--;
2414 } else if (strcmp (element_name, "startup") == 0) {
2415 app_config->startup_count--;
2419 static const GMarkupParser
2420 mono_parser = {
2421 start_element,
2422 end_element,
2423 NULL,
2424 NULL,
2425 NULL
2428 static AppConfigInfo *
2429 app_config_parse (const char *exe_filename)
2431 AppConfigInfo *app_config;
2432 GMarkupParseContext *context;
2433 char *text;
2434 gsize len;
2435 const char *bundled_config;
2436 char *config_filename;
2438 bundled_config = mono_config_string_for_assembly_file (exe_filename);
2440 if (bundled_config) {
2441 text = g_strdup (bundled_config);
2442 len = strlen (text);
2443 } else {
2444 config_filename = g_strconcat (exe_filename, ".config", NULL);
2446 if (!g_file_get_contents (config_filename, &text, &len, NULL)) {
2447 g_free (config_filename);
2448 return NULL;
2450 g_free (config_filename);
2453 app_config = g_new0 (AppConfigInfo, 1);
2455 context = g_markup_parse_context_new (&mono_parser, 0, app_config, NULL);
2456 if (g_markup_parse_context_parse (context, text, len, NULL)) {
2457 g_markup_parse_context_end_parse (context, NULL);
2459 g_markup_parse_context_free (context);
2460 g_free (text);
2461 return app_config;
2464 static void
2465 app_config_free (AppConfigInfo* app_config)
2467 char *rt;
2468 GSList *list = app_config->supported_runtimes;
2469 while (list != NULL) {
2470 rt = (char*)list->data;
2471 g_free (rt);
2472 list = g_slist_next (list);
2474 g_slist_free (app_config->supported_runtimes);
2475 g_free (app_config->required_runtime);
2476 g_free (app_config);
2480 static const MonoRuntimeInfo*
2481 get_runtime_by_version (const char *version)
2483 int n;
2484 int max = G_N_ELEMENTS (supported_runtimes);
2486 for (n=0; n<max; n++) {
2487 if (strcmp (version, supported_runtimes[n].runtime_version) == 0)
2488 return &supported_runtimes[n];
2490 return NULL;
2493 static void
2494 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes)
2496 AppConfigInfo* app_config;
2497 char *version;
2498 const MonoRuntimeInfo* runtime = NULL;
2499 MonoImage *image = NULL;
2501 app_config = app_config_parse (exe_file);
2503 if (app_config != NULL) {
2504 /* Check supportedRuntime elements, if none is supported, fail.
2505 * If there are no such elements, look for a requiredRuntime element.
2507 if (app_config->supported_runtimes != NULL) {
2508 int n = 0;
2509 GSList *list = app_config->supported_runtimes;
2510 while (list != NULL) {
2511 version = (char*) list->data;
2512 runtime = get_runtime_by_version (version);
2513 if (runtime != NULL)
2514 runtimes [n++] = runtime;
2515 list = g_slist_next (list);
2517 runtimes [n] = NULL;
2518 app_config_free (app_config);
2519 return;
2522 /* Check the requiredRuntime element. This is for 1.0 apps only. */
2523 if (app_config->required_runtime != NULL) {
2524 runtimes [0] = get_runtime_by_version (app_config->required_runtime);
2525 runtimes [1] = NULL;
2526 app_config_free (app_config);
2527 return;
2529 app_config_free (app_config);
2532 /* Look for a runtime with the exact version */
2533 image = mono_assembly_open_from_bundle (exe_file, NULL, FALSE);
2535 if (image == NULL)
2536 image = mono_image_open (exe_file, NULL);
2538 if (image == NULL) {
2539 /* The image is wrong or the file was not found. In this case return
2540 * a default runtime and leave to the initialization method the work of
2541 * reporting the error.
2543 runtimes [0] = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
2544 runtimes [1] = NULL;
2545 return;
2548 *exe_image = image;
2550 runtimes [0] = get_runtime_by_version (image->version);
2551 runtimes [1] = NULL;
2556 * mono_get_runtime_info:
2558 * Returns: the version of the current runtime instance.
2560 const MonoRuntimeInfo*
2561 mono_get_runtime_info (void)
2563 return current_runtime;
2566 gchar *
2567 mono_debugger_check_runtime_version (const char *filename)
2569 const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
2570 const MonoRuntimeInfo *rinfo;
2571 MonoImage *image;
2573 get_runtimes_from_exe (filename, &image, runtimes);
2574 rinfo = runtimes [0];
2576 if (!rinfo)
2577 return g_strdup_printf ("Cannot get runtime version from assembly `%s'", filename);
2579 if (rinfo != current_runtime)
2580 return g_strdup_printf ("The Mono Debugger is currently using the `%s' runtime, but "
2581 "the assembly `%s' requires version `%s'", current_runtime->runtime_version,
2582 filename, rinfo->runtime_version);
2584 return NULL;
2588 * mono_framework_version:
2590 * Return the major version of the framework curently executing.
2593 mono_framework_version (void)
2595 return current_runtime->framework_version [0] - '0';