2009-11-23 Andreas Faerber <andreas.faerber@web.de>
[mono.git] / mono / metadata / domain.c
blobbc0f581452345546973d11a0afce8cd2153f086c
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 {"moonlight", "2.1", { {2,0,5,0}, {9,0,0,0} } },
140 /* The stable runtime version */
141 #define DEFAULT_RUNTIME_VERSION "v2.0.50727"
143 /* Callbacks installed by the JIT */
144 static MonoCreateDomainFunc create_domain_hook;
145 static MonoFreeDomainFunc free_domain_hook;
147 /* This is intentionally not in the header file, so people don't misuse it. */
148 extern void _mono_debug_init_corlib (MonoDomain *domain);
150 static void
151 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes);
153 static const MonoRuntimeInfo*
154 get_runtime_by_version (const char *version);
156 static MonoImage*
157 mono_jit_info_find_aot_module (guint8* addr);
159 guint32
160 mono_domain_get_tls_key (void)
162 #ifdef NO_TLS_SET_VALUE
163 g_assert_not_reached ();
164 return 0;
165 #else
166 return appdomain_thread_id;
167 #endif
170 gint32
171 mono_domain_get_tls_offset (void)
173 int offset = -1;
174 MONO_THREAD_VAR_OFFSET (tls_appdomain, offset);
175 /* __asm ("jmp 1f; .section writetext, \"awx\"; 1: movl $tls_appdomain@ntpoff, %0; jmp 2f; .previous; 2:"
176 : "=r" (offset));*/
177 return offset;
180 #define JIT_INFO_TABLE_FILL_RATIO_NOM 3
181 #define JIT_INFO_TABLE_FILL_RATIO_DENOM 4
182 #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)
184 #define JIT_INFO_TABLE_LOW_WATERMARK(n) ((n) / 2)
185 #define JIT_INFO_TABLE_HIGH_WATERMARK(n) ((n) * 5 / 6)
187 #define JIT_INFO_TOMBSTONE_MARKER ((MonoMethod*)NULL)
188 #define IS_JIT_INFO_TOMBSTONE(ji) ((ji)->method == JIT_INFO_TOMBSTONE_MARKER)
190 #define JIT_INFO_TABLE_HAZARD_INDEX 0
191 #define JIT_INFO_HAZARD_INDEX 1
193 static int
194 jit_info_table_num_elements (MonoJitInfoTable *table)
196 int i;
197 int num_elements = 0;
199 for (i = 0; i < table->num_chunks; ++i) {
200 MonoJitInfoTableChunk *chunk = table->chunks [i];
201 int chunk_num_elements = chunk->num_elements;
202 int j;
204 for (j = 0; j < chunk_num_elements; ++j) {
205 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j]))
206 ++num_elements;
210 return num_elements;
213 static MonoJitInfoTableChunk*
214 jit_info_table_new_chunk (void)
216 MonoJitInfoTableChunk *chunk = g_new0 (MonoJitInfoTableChunk, 1);
217 chunk->refcount = 1;
219 return chunk;
222 static MonoJitInfoTable *
223 jit_info_table_new (MonoDomain *domain)
225 MonoJitInfoTable *table = g_malloc0 (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*));
227 table->domain = domain;
228 table->num_chunks = 1;
229 table->chunks [0] = jit_info_table_new_chunk ();
231 return table;
234 static void
235 jit_info_table_free (MonoJitInfoTable *table)
237 int i;
238 int num_chunks = table->num_chunks;
239 MonoDomain *domain = table->domain;
241 mono_domain_lock (domain);
243 table->domain->num_jit_info_tables--;
244 if (table->domain->num_jit_info_tables <= 1) {
245 GSList *list;
247 for (list = table->domain->jit_info_free_queue; list; list = list->next)
248 g_free (list->data);
250 g_slist_free (table->domain->jit_info_free_queue);
251 table->domain->jit_info_free_queue = NULL;
254 /* At this point we assume that there are no other threads
255 still accessing the table, so we don't have to worry about
256 hazardous pointers. */
258 for (i = 0; i < num_chunks; ++i) {
259 MonoJitInfoTableChunk *chunk = table->chunks [i];
260 int num_elements;
261 int j;
263 if (--chunk->refcount > 0)
264 continue;
266 num_elements = chunk->num_elements;
267 for (j = 0; j < num_elements; ++j) {
268 MonoJitInfo *ji = chunk->data [j];
270 if (IS_JIT_INFO_TOMBSTONE (ji))
271 g_free (ji);
274 g_free (chunk);
277 mono_domain_unlock (domain);
279 g_free (table);
282 /* Can be called with hp==NULL, in which case it acts as an ordinary
283 pointer fetch. It's used that way indirectly from
284 mono_jit_info_table_add(), which doesn't have to care about hazards
285 because it holds the respective domain lock. */
286 static gpointer
287 get_hazardous_pointer (gpointer volatile *pp, MonoThreadHazardPointers *hp, int hazard_index)
289 gpointer p;
291 for (;;) {
292 /* Get the pointer */
293 p = *pp;
294 /* If we don't have hazard pointers just return the
295 pointer. */
296 if (!hp)
297 return p;
298 /* Make it hazardous */
299 mono_hazard_pointer_set (hp, hazard_index, p);
300 /* Check that it's still the same. If not, try
301 again. */
302 if (*pp != p) {
303 mono_hazard_pointer_clear (hp, hazard_index);
304 continue;
306 break;
309 return p;
312 /* The jit_info_table is sorted in ascending order by the end
313 * addresses of the compiled methods. The reason why we have to do
314 * this is that once we introduce tombstones, it becomes possible for
315 * code ranges to overlap, and if we sort by code start and insert at
316 * the back of the table, we cannot guarantee that we won't overlook
317 * an entry.
319 * There are actually two possible ways to do the sorting and
320 * inserting which work with our lock-free mechanism:
322 * 1. Sort by start address and insert at the front. When looking for
323 * an entry, find the last one with a start address lower than the one
324 * you're looking for, then work your way to the front of the table.
326 * 2. Sort by end address and insert at the back. When looking for an
327 * entry, find the first one with an end address higher than the one
328 * you're looking for, then work your way to the end of the table.
330 * We chose the latter out of convenience.
332 static int
333 jit_info_table_index (MonoJitInfoTable *table, gint8 *addr)
335 int left = 0, right = table->num_chunks;
337 g_assert (left < right);
339 do {
340 int pos = (left + right) / 2;
341 MonoJitInfoTableChunk *chunk = table->chunks [pos];
343 if (addr < chunk->last_code_end)
344 right = pos;
345 else
346 left = pos + 1;
347 } while (left < right);
348 g_assert (left == right);
350 if (left >= table->num_chunks)
351 return table->num_chunks - 1;
352 return left;
355 static int
356 jit_info_table_chunk_index (MonoJitInfoTableChunk *chunk, MonoThreadHazardPointers *hp, gint8 *addr)
358 int left = 0, right = chunk->num_elements;
360 while (left < right) {
361 int pos = (left + right) / 2;
362 MonoJitInfo *ji = get_hazardous_pointer((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
363 gint8 *code_end = (gint8*)ji->code_start + ji->code_size;
365 if (addr < code_end)
366 right = pos;
367 else
368 left = pos + 1;
370 g_assert (left == right);
372 return left;
375 MonoJitInfo*
376 mono_jit_info_table_find (MonoDomain *domain, char *addr)
378 MonoJitInfoTable *table;
379 MonoJitInfo *ji;
380 int chunk_pos, pos;
381 MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
383 ++mono_stats.jit_info_table_lookup_count;
385 /* First we have to get the domain's jit_info_table. This is
386 complicated by the fact that a writer might substitute a
387 new table and free the old one. What the writer guarantees
388 us is that it looks at the hazard pointers after it has
389 changed the jit_info_table pointer. So, if we guard the
390 table by a hazard pointer and make sure that the pointer is
391 still there after we've made it hazardous, we don't have to
392 worry about the writer freeing the table. */
393 table = get_hazardous_pointer ((gpointer volatile*)&domain->jit_info_table, hp, JIT_INFO_TABLE_HAZARD_INDEX);
395 chunk_pos = jit_info_table_index (table, (gint8*)addr);
396 g_assert (chunk_pos < table->num_chunks);
398 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], hp, (gint8*)addr);
400 /* We now have a position that's very close to that of the
401 first element whose end address is higher than the one
402 we're looking for. If we don't have the exact position,
403 then we have a position below that one, so we'll just
404 search upward until we find our element. */
405 do {
406 MonoJitInfoTableChunk *chunk = table->chunks [chunk_pos];
408 while (pos < chunk->num_elements) {
409 ji = get_hazardous_pointer ((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
411 ++pos;
413 if (IS_JIT_INFO_TOMBSTONE (ji)) {
414 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
415 continue;
417 if ((gint8*)addr >= (gint8*)ji->code_start
418 && (gint8*)addr < (gint8*)ji->code_start + ji->code_size) {
419 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
420 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
421 return ji;
424 /* If we find a non-tombstone element which is already
425 beyond what we're looking for, we have to end the
426 search. */
427 if ((gint8*)addr < (gint8*)ji->code_start)
428 goto not_found;
431 ++chunk_pos;
432 pos = 0;
433 } while (chunk_pos < table->num_chunks);
435 not_found:
436 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
437 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
439 /* maybe it is shared code, so we also search in the root domain */
440 ji = NULL;
441 if (domain != mono_root_domain)
442 ji = mono_jit_info_table_find (mono_root_domain, addr);
444 if (ji == NULL) {
445 /* Maybe its an AOT module */
446 MonoImage *image = mono_jit_info_find_aot_module ((guint8*)addr);
447 if (image)
448 ji = jit_info_find_in_aot_func (domain, image, addr);
451 return ji;
454 static G_GNUC_UNUSED void
455 jit_info_table_check (MonoJitInfoTable *table)
457 int i;
459 for (i = 0; i < table->num_chunks; ++i) {
460 MonoJitInfoTableChunk *chunk = table->chunks [i];
461 int j;
463 g_assert (chunk->refcount > 0 /* && chunk->refcount <= 8 */);
464 if (chunk->refcount > 10)
465 printf("warning: chunk refcount is %d\n", chunk->refcount);
466 g_assert (chunk->num_elements <= MONO_JIT_INFO_TABLE_CHUNK_SIZE);
468 for (j = 0; j < chunk->num_elements; ++j) {
469 MonoJitInfo *this = chunk->data [j];
470 MonoJitInfo *next;
472 g_assert ((gint8*)this->code_start + this->code_size <= chunk->last_code_end);
474 if (j < chunk->num_elements - 1)
475 next = chunk->data [j + 1];
476 else if (i < table->num_chunks - 1) {
477 int k;
479 for (k = i + 1; k < table->num_chunks; ++k)
480 if (table->chunks [k]->num_elements > 0)
481 break;
483 if (k >= table->num_chunks)
484 return;
486 g_assert (table->chunks [k]->num_elements > 0);
487 next = table->chunks [k]->data [0];
488 } else
489 return;
491 g_assert ((gint8*)this->code_start + this->code_size <= (gint8*)next->code_start + next->code_size);
496 static MonoJitInfoTable*
497 jit_info_table_realloc (MonoJitInfoTable *old)
499 int i;
500 int num_elements = jit_info_table_num_elements (old);
501 int required_size;
502 int num_chunks;
503 int new_chunk, new_element;
504 MonoJitInfoTable *new;
506 /* number of needed places for elements needed */
507 required_size = (int)((long)num_elements * JIT_INFO_TABLE_FILL_RATIO_DENOM / JIT_INFO_TABLE_FILL_RATIO_NOM);
508 num_chunks = (required_size + MONO_JIT_INFO_TABLE_CHUNK_SIZE - 1) / MONO_JIT_INFO_TABLE_CHUNK_SIZE;
510 new = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*) * num_chunks);
511 new->domain = old->domain;
512 new->num_chunks = num_chunks;
514 for (i = 0; i < num_chunks; ++i)
515 new->chunks [i] = jit_info_table_new_chunk ();
517 new_chunk = 0;
518 new_element = 0;
519 for (i = 0; i < old->num_chunks; ++i) {
520 MonoJitInfoTableChunk *chunk = old->chunks [i];
521 int chunk_num_elements = chunk->num_elements;
522 int j;
524 for (j = 0; j < chunk_num_elements; ++j) {
525 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j])) {
526 g_assert (new_chunk < num_chunks);
527 new->chunks [new_chunk]->data [new_element] = chunk->data [j];
528 if (++new_element >= JIT_INFO_TABLE_FILLED_NUM_ELEMENTS) {
529 new->chunks [new_chunk]->num_elements = new_element;
530 ++new_chunk;
531 new_element = 0;
537 if (new_chunk < num_chunks) {
538 g_assert (new_chunk == num_chunks - 1);
539 new->chunks [new_chunk]->num_elements = new_element;
540 g_assert (new->chunks [new_chunk]->num_elements > 0);
543 for (i = 0; i < num_chunks; ++i) {
544 MonoJitInfoTableChunk *chunk = new->chunks [i];
545 MonoJitInfo *ji = chunk->data [chunk->num_elements - 1];
547 new->chunks [i]->last_code_end = (gint8*)ji->code_start + ji->code_size;
550 return new;
553 static void
554 jit_info_table_split_chunk (MonoJitInfoTableChunk *chunk, MonoJitInfoTableChunk **new1p, MonoJitInfoTableChunk **new2p)
556 MonoJitInfoTableChunk *new1 = jit_info_table_new_chunk ();
557 MonoJitInfoTableChunk *new2 = jit_info_table_new_chunk ();
559 g_assert (chunk->num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE);
561 new1->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE / 2;
562 new2->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE - new1->num_elements;
564 memcpy ((void*)new1->data, (void*)chunk->data, sizeof (MonoJitInfo*) * new1->num_elements);
565 memcpy ((void*)new2->data, (void*)(chunk->data + new1->num_elements), sizeof (MonoJitInfo*) * new2->num_elements);
567 new1->last_code_end = (gint8*)new1->data [new1->num_elements - 1]->code_start
568 + new1->data [new1->num_elements - 1]->code_size;
569 new2->last_code_end = (gint8*)new2->data [new2->num_elements - 1]->code_start
570 + new2->data [new2->num_elements - 1]->code_size;
572 *new1p = new1;
573 *new2p = new2;
576 static MonoJitInfoTable*
577 jit_info_table_copy_and_split_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
579 MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
580 + sizeof (MonoJitInfoTableChunk*) * (table->num_chunks + 1));
581 int i, j;
583 new_table->domain = table->domain;
584 new_table->num_chunks = table->num_chunks + 1;
586 j = 0;
587 for (i = 0; i < table->num_chunks; ++i) {
588 if (table->chunks [i] == chunk) {
589 jit_info_table_split_chunk (chunk, &new_table->chunks [j], &new_table->chunks [j + 1]);
590 j += 2;
591 } else {
592 new_table->chunks [j] = table->chunks [i];
593 ++new_table->chunks [j]->refcount;
594 ++j;
598 g_assert (j == new_table->num_chunks);
600 return new_table;
603 static MonoJitInfoTableChunk*
604 jit_info_table_purify_chunk (MonoJitInfoTableChunk *old)
606 MonoJitInfoTableChunk *new = jit_info_table_new_chunk ();
607 int i, j;
609 j = 0;
610 for (i = 0; i < old->num_elements; ++i) {
611 if (!IS_JIT_INFO_TOMBSTONE (old->data [i]))
612 new->data [j++] = old->data [i];
615 new->num_elements = j;
616 if (new->num_elements > 0)
617 new->last_code_end = (gint8*)new->data [j - 1]->code_start + new->data [j - 1]->code_size;
618 else
619 new->last_code_end = old->last_code_end;
621 return new;
624 static MonoJitInfoTable*
625 jit_info_table_copy_and_purify_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
627 MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
628 + sizeof (MonoJitInfoTableChunk*) * table->num_chunks);
629 int i, j;
631 new_table->domain = table->domain;
632 new_table->num_chunks = table->num_chunks;
634 j = 0;
635 for (i = 0; i < table->num_chunks; ++i) {
636 if (table->chunks [i] == chunk)
637 new_table->chunks [j++] = jit_info_table_purify_chunk (table->chunks [i]);
638 else {
639 new_table->chunks [j] = table->chunks [i];
640 ++new_table->chunks [j]->refcount;
641 ++j;
645 g_assert (j == new_table->num_chunks);
647 return new_table;
650 /* As we add an element to the table the case can arise that the chunk
651 * to which we need to add is already full. In that case we have to
652 * allocate a new table and do something about that chunk. We have
653 * several strategies:
655 * If the number of elements in the table is below the low watermark
656 * or above the high watermark, we reallocate the whole table.
657 * Otherwise we only concern ourselves with the overflowing chunk:
659 * If there are no tombstones in the chunk then we split the chunk in
660 * two, each half full.
662 * If the chunk does contain tombstones, we just make a new copy of
663 * the chunk without the tombstones, which will have room for at least
664 * the one element we have to add.
666 static MonoJitInfoTable*
667 jit_info_table_chunk_overflow (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
669 int num_elements = jit_info_table_num_elements (table);
670 int i;
672 if (num_elements < JIT_INFO_TABLE_LOW_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)
673 || num_elements > JIT_INFO_TABLE_HIGH_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)) {
674 //printf ("reallocing table\n");
675 return jit_info_table_realloc (table);
678 /* count the number of non-tombstone elements in the chunk */
679 num_elements = 0;
680 for (i = 0; i < chunk->num_elements; ++i) {
681 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [i]))
682 ++num_elements;
685 if (num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
686 //printf ("splitting chunk\n");
687 return jit_info_table_copy_and_split_chunk (table, chunk);
690 //printf ("purifying chunk\n");
691 return jit_info_table_copy_and_purify_chunk (table, chunk);
694 /* We add elements to the table by first making space for them by
695 * shifting the elements at the back to the right, one at a time.
696 * This results in duplicate entries during the process, but during
697 * all the time the table is in a sorted state. Also, when an element
698 * is replaced by another one, the element that replaces it has an end
699 * address that is equal to or lower than that of the replaced
700 * element. That property is necessary to guarantee that when
701 * searching for an element we end up at a position not higher than
702 * the one we're looking for (i.e. we either find the element directly
703 * or we end up to the left of it).
705 void
706 mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
708 MonoJitInfoTable *table;
709 int chunk_pos, pos;
710 MonoJitInfoTableChunk *chunk;
711 int num_elements;
712 int i;
714 g_assert (ji->method != NULL);
716 mono_domain_lock (domain);
718 ++mono_stats.jit_info_table_insert_count;
720 table = domain->jit_info_table;
722 restart:
723 chunk_pos = jit_info_table_index (table, (gint8*)ji->code_start + ji->code_size);
724 g_assert (chunk_pos < table->num_chunks);
725 chunk = table->chunks [chunk_pos];
727 if (chunk->num_elements >= MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
728 MonoJitInfoTable *new_table = jit_info_table_chunk_overflow (table, chunk);
730 /* Debugging code, should be removed. */
731 //jit_info_table_check (new_table);
733 domain->jit_info_table = new_table;
734 mono_memory_barrier ();
735 domain->num_jit_info_tables++;
736 mono_thread_hazardous_free_or_queue (table, (MonoHazardousFreeFunc)jit_info_table_free);
737 table = new_table;
739 goto restart;
742 /* Debugging code, should be removed. */
743 //jit_info_table_check (table);
745 num_elements = chunk->num_elements;
747 pos = jit_info_table_chunk_index (chunk, NULL, (gint8*)ji->code_start + ji->code_size);
749 /* First we need to size up the chunk by one, by copying the
750 last item, or inserting the first one, if the table is
751 empty. */
752 if (num_elements > 0)
753 chunk->data [num_elements] = chunk->data [num_elements - 1];
754 else
755 chunk->data [0] = ji;
756 mono_memory_write_barrier ();
757 chunk->num_elements = ++num_elements;
759 /* Shift the elements up one by one. */
760 for (i = num_elements - 2; i >= pos; --i) {
761 mono_memory_write_barrier ();
762 chunk->data [i + 1] = chunk->data [i];
765 /* Now we have room and can insert the new item. */
766 mono_memory_write_barrier ();
767 chunk->data [pos] = ji;
769 /* Set the high code end address chunk entry. */
770 chunk->last_code_end = (gint8*)chunk->data [chunk->num_elements - 1]->code_start
771 + chunk->data [chunk->num_elements - 1]->code_size;
773 /* Debugging code, should be removed. */
774 //jit_info_table_check (table);
776 mono_domain_unlock (domain);
779 static MonoJitInfo*
780 mono_jit_info_make_tombstone (MonoJitInfo *ji)
782 MonoJitInfo *tombstone = g_new0 (MonoJitInfo, 1);
784 tombstone->code_start = ji->code_start;
785 tombstone->code_size = ji->code_size;
786 tombstone->method = JIT_INFO_TOMBSTONE_MARKER;
788 return tombstone;
792 * LOCKING: domain lock
794 static void
795 mono_jit_info_free_or_queue (MonoDomain *domain, MonoJitInfo *ji)
797 if (domain->num_jit_info_tables <= 1) {
798 /* Can it actually happen that we only have one table
799 but ji is still hazardous? */
800 mono_thread_hazardous_free_or_queue (ji, g_free);
801 } else {
802 domain->jit_info_free_queue = g_slist_prepend (domain->jit_info_free_queue, ji);
806 void
807 mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
809 MonoJitInfoTable *table;
810 MonoJitInfoTableChunk *chunk;
811 gpointer start = ji->code_start;
812 int chunk_pos, pos;
814 mono_domain_lock (domain);
815 table = domain->jit_info_table;
817 ++mono_stats.jit_info_table_remove_count;
819 chunk_pos = jit_info_table_index (table, start);
820 g_assert (chunk_pos < table->num_chunks);
822 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], NULL, start);
824 do {
825 chunk = table->chunks [chunk_pos];
827 while (pos < chunk->num_elements) {
828 if (chunk->data [pos] == ji)
829 goto found;
831 g_assert (IS_JIT_INFO_TOMBSTONE (chunk->data [pos]));
832 g_assert ((guint8*)chunk->data [pos]->code_start + chunk->data [pos]->code_size
833 <= (guint8*)ji->code_start + ji->code_size);
835 ++pos;
838 ++chunk_pos;
839 pos = 0;
840 } while (chunk_pos < table->num_chunks);
842 found:
843 g_assert (chunk->data [pos] == ji);
845 chunk->data [pos] = mono_jit_info_make_tombstone (ji);
847 /* Debugging code, should be removed. */
848 //jit_info_table_check (table);
850 mono_jit_info_free_or_queue (domain, ji);
852 mono_domain_unlock (domain);
855 static MonoAotModuleInfoTable*
856 mono_aot_module_info_table_new (void)
858 return g_array_new (FALSE, FALSE, sizeof (gpointer));
861 static int
862 aot_info_table_index (MonoAotModuleInfoTable *table, char *addr)
864 int left = 0, right = table->len;
866 while (left < right) {
867 int pos = (left + right) / 2;
868 AotModuleInfo *ainfo = g_array_index (table, gpointer, pos);
869 char *start = ainfo->start;
870 char *end = ainfo->end;
872 if (addr < start)
873 right = pos;
874 else if (addr >= end)
875 left = pos + 1;
876 else
877 return pos;
880 return left;
883 void
884 mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
886 AotModuleInfo *ainfo = g_new0 (AotModuleInfo, 1);
887 int pos;
889 ainfo->image = image;
890 ainfo->start = start;
891 ainfo->end = end;
893 mono_appdomains_lock ();
895 if (!aot_modules)
896 aot_modules = mono_aot_module_info_table_new ();
898 pos = aot_info_table_index (aot_modules, start);
900 g_array_insert_val (aot_modules, pos, ainfo);
902 mono_appdomains_unlock ();
905 static MonoImage*
906 mono_jit_info_find_aot_module (guint8* addr)
908 guint left = 0, right;
910 if (!aot_modules)
911 return NULL;
913 mono_appdomains_lock ();
915 right = aot_modules->len;
916 while (left < right) {
917 guint pos = (left + right) / 2;
918 AotModuleInfo *ai = g_array_index (aot_modules, gpointer, pos);
920 if (addr < (guint8*)ai->start)
921 right = pos;
922 else if (addr >= (guint8*)ai->end)
923 left = pos + 1;
924 else {
925 mono_appdomains_unlock ();
926 return ai->image;
930 mono_appdomains_unlock ();
932 return NULL;
935 void
936 mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func)
938 jit_info_find_in_aot_func = func;
941 gpointer
942 mono_jit_info_get_code_start (MonoJitInfo* ji)
944 return ji->code_start;
948 mono_jit_info_get_code_size (MonoJitInfo* ji)
950 return ji->code_size;
953 MonoMethod*
954 mono_jit_info_get_method (MonoJitInfo* ji)
956 return ji->method;
959 static gpointer
960 jit_info_key_extract (gpointer value)
962 MonoJitInfo *info = (MonoJitInfo*)value;
964 return info->method;
967 static gpointer*
968 jit_info_next_value (gpointer value)
970 MonoJitInfo *info = (MonoJitInfo*)value;
972 return (gpointer*)&info->next_jit_code_hash;
975 void
976 mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
978 mono_internal_hash_table_init (jit_code_hash,
979 mono_aligned_addr_hash,
980 jit_info_key_extract,
981 jit_info_next_value);
984 MonoGenericJitInfo*
985 mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
987 if (ji->has_generic_jit_info)
988 return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
989 else
990 return NULL;
994 * mono_jit_info_get_generic_sharing_context:
995 * @ji: a jit info
997 * Returns the jit info's generic sharing context, or NULL if it
998 * doesn't have one.
1000 MonoGenericSharingContext*
1001 mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
1003 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
1005 if (gi)
1006 return gi->generic_sharing_context;
1007 else
1008 return NULL;
1012 * mono_jit_info_set_generic_sharing_context:
1013 * @ji: a jit info
1014 * @gsctx: a generic sharing context
1016 * Sets the jit info's generic sharing context. The jit info must
1017 * have memory allocated for the context.
1019 void
1020 mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
1022 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
1024 g_assert (gi);
1026 gi->generic_sharing_context = gsctx;
1029 void
1030 mono_install_create_domain_hook (MonoCreateDomainFunc func)
1032 create_domain_hook = func;
1035 void
1036 mono_install_free_domain_hook (MonoFreeDomainFunc func)
1038 free_domain_hook = func;
1042 * mono_string_equal:
1043 * @s1: First string to compare
1044 * @s2: Second string to compare
1046 * Returns FALSE if the strings differ.
1048 gboolean
1049 mono_string_equal (MonoString *s1, MonoString *s2)
1051 int l1 = mono_string_length (s1);
1052 int l2 = mono_string_length (s2);
1054 if (s1 == s2)
1055 return TRUE;
1056 if (l1 != l2)
1057 return FALSE;
1059 return memcmp (mono_string_chars (s1), mono_string_chars (s2), l1 * 2) == 0;
1063 * mono_string_hash:
1064 * @s: the string to hash
1066 * Returns the hash for the string.
1068 guint
1069 mono_string_hash (MonoString *s)
1071 const guint16 *p = mono_string_chars (s);
1072 int i, len = mono_string_length (s);
1073 guint h = 0;
1075 for (i = 0; i < len; i++) {
1076 h = (h << 5) - h + *p;
1077 p++;
1080 return h;
1083 static gboolean
1084 mono_ptrarray_equal (gpointer *s1, gpointer *s2)
1086 int len = GPOINTER_TO_INT (s1 [0]);
1087 if (len != GPOINTER_TO_INT (s2 [0]))
1088 return FALSE;
1090 return memcmp (s1 + 1, s2 + 1, len * sizeof(gpointer)) == 0;
1093 static guint
1094 mono_ptrarray_hash (gpointer *s)
1096 int i;
1097 int len = GPOINTER_TO_INT (s [0]);
1098 guint hash = 0;
1100 for (i = 1; i < len; i++)
1101 hash += GPOINTER_TO_UINT (s [i]);
1103 return hash;
1107 * Allocate an id for domain and set domain->domain_id.
1108 * LOCKING: must be called while holding appdomains_mutex.
1109 * We try to assign low numbers to the domain, so it can be used
1110 * as an index in data tables to lookup domain-specific info
1111 * with minimal memory overhead. We also try not to reuse the
1112 * same id too quickly (to help debugging).
1114 static int
1115 domain_id_alloc (MonoDomain *domain)
1117 int id = -1, i;
1118 if (!appdomains_list) {
1119 appdomain_list_size = 2;
1120 appdomains_list = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1122 for (i = appdomain_next; i < appdomain_list_size; ++i) {
1123 if (!appdomains_list [i]) {
1124 id = i;
1125 break;
1128 if (id == -1) {
1129 for (i = 0; i < appdomain_next; ++i) {
1130 if (!appdomains_list [i]) {
1131 id = i;
1132 break;
1136 if (id == -1) {
1137 MonoDomain **new_list;
1138 int new_size = appdomain_list_size * 2;
1139 if (new_size >= (1 << 16))
1140 g_assert_not_reached ();
1141 id = appdomain_list_size;
1142 new_list = mono_gc_alloc_fixed (new_size * sizeof (void*), NULL);
1143 memcpy (new_list, appdomains_list, appdomain_list_size * sizeof (void*));
1144 mono_gc_free_fixed (appdomains_list);
1145 appdomains_list = new_list;
1146 appdomain_list_size = new_size;
1148 domain->domain_id = id;
1149 appdomains_list [id] = domain;
1150 appdomain_next++;
1151 if (appdomain_next > appdomain_list_size)
1152 appdomain_next = 0;
1153 return id;
1156 static guint32 domain_gc_bitmap [sizeof(MonoDomain)/4/32 + 1];
1157 static gpointer domain_gc_desc = NULL;
1158 static guint32 domain_shadow_serial = 0L;
1160 MonoDomain *
1161 mono_domain_create (void)
1163 MonoDomain *domain;
1164 guint32 shadow_serial;
1166 mono_appdomains_lock ();
1167 shadow_serial = domain_shadow_serial++;
1169 if (!domain_gc_desc) {
1170 unsigned int i, bit = 0;
1171 for (i = G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_OBJECT); i < G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_GC_TRACKED); i += sizeof (gpointer)) {
1172 bit = i / sizeof (gpointer);
1173 domain_gc_bitmap [bit / 32] |= 1 << (bit % 32);
1175 domain_gc_desc = mono_gc_make_descr_from_bitmap ((gsize*)domain_gc_bitmap, bit + 1);
1177 mono_appdomains_unlock ();
1179 domain = mono_gc_alloc_fixed (sizeof (MonoDomain), domain_gc_desc);
1180 domain->shadow_serial = shadow_serial;
1181 domain->domain = NULL;
1182 domain->setup = NULL;
1183 domain->friendly_name = NULL;
1184 domain->search_path = NULL;
1186 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);
1188 mono_profiler_appdomain_event (domain, MONO_PROFILE_START_LOAD);
1190 domain->mp = mono_mempool_new ();
1191 domain->code_mp = mono_code_manager_new ();
1192 domain->env = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1193 domain->domain_assemblies = NULL;
1194 domain->class_vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1195 domain->proxy_vtable_hash = g_hash_table_new ((GHashFunc)mono_ptrarray_hash, (GCompareFunc)mono_ptrarray_equal);
1196 domain->static_data_array = NULL;
1197 mono_jit_code_hash_init (&domain->jit_code_hash);
1198 domain->ldstr_table = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1199 domain->num_jit_info_tables = 1;
1200 domain->jit_info_table = jit_info_table_new (domain);
1201 domain->jit_info_free_queue = NULL;
1202 domain->finalizable_objects_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1203 #ifndef HAVE_SGEN_GC
1204 domain->track_resurrection_handles_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1205 #endif
1207 InitializeCriticalSection (&domain->lock);
1208 InitializeCriticalSection (&domain->assemblies_lock);
1209 InitializeCriticalSection (&domain->jit_code_hash_lock);
1210 InitializeCriticalSection (&domain->finalizable_objects_hash_lock);
1212 domain->method_rgctx_hash = NULL;
1214 mono_appdomains_lock ();
1215 domain_id_alloc (domain);
1216 mono_appdomains_unlock ();
1218 mono_perfcounters->loader_appdomains++;
1219 mono_perfcounters->loader_total_appdomains++;
1221 mono_debug_domain_create (domain);
1223 if (create_domain_hook)
1224 create_domain_hook (domain);
1226 mono_profiler_appdomain_loaded (domain, MONO_PROFILE_OK);
1228 return domain;
1232 * mono_init_internal:
1234 * Creates the initial application domain and initializes the mono_defaults
1235 * structure.
1236 * This function is guaranteed to not run any IL code.
1237 * If exe_filename is not NULL, the method will determine the required runtime
1238 * from the exe configuration file or the version PE field.
1239 * If runtime_version is not NULL, that runtime version will be used.
1240 * Either exe_filename or runtime_version must be provided.
1242 * Returns: the initial domain.
1244 static MonoDomain *
1245 mono_init_internal (const char *filename, const char *exe_filename, const char *runtime_version)
1247 static MonoDomain *domain = NULL;
1248 MonoAssembly *ass = NULL;
1249 MonoImageOpenStatus status = MONO_IMAGE_OK;
1250 const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
1251 int n;
1253 if (domain)
1254 g_assert_not_reached ();
1256 #ifdef HOST_WIN32
1257 /* Avoid system error message boxes. */
1258 SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1260 mono_load_coree (exe_filename);
1261 #endif
1263 mono_perfcounters_init ();
1265 mono_counters_register ("Max native code in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_size);
1266 mono_counters_register ("Max code space allocated in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_alloc);
1267 mono_counters_register ("Total code space allocated", MONO_COUNTER_INT|MONO_COUNTER_JIT, &total_domain_code_alloc);
1269 mono_gc_base_init ();
1271 appdomain_thread_id = TlsAlloc ();
1273 InitializeCriticalSection (&appdomains_mutex);
1275 mono_metadata_init ();
1276 mono_images_init ();
1277 mono_assemblies_init ();
1278 mono_classes_init ();
1279 mono_loader_init ();
1280 mono_reflection_init ();
1282 /* FIXME: When should we release this memory? */
1283 MONO_GC_REGISTER_ROOT (appdomains_list);
1285 domain = mono_domain_create ();
1286 mono_root_domain = domain;
1288 SET_APPDOMAIN (domain);
1290 /* Get a list of runtimes supported by the exe */
1291 if (exe_filename != NULL) {
1293 * This function will load the exe file as a MonoImage. We need to close it, but
1294 * that would mean it would be reloaded later. So instead, we save it to
1295 * exe_image, and close it during shutdown.
1297 get_runtimes_from_exe (exe_filename, &exe_image, runtimes);
1298 #ifdef HOST_WIN32
1299 if (!exe_image) {
1300 exe_image = mono_assembly_open_from_bundle (exe_filename, NULL, FALSE);
1301 if (!exe_image)
1302 exe_image = mono_image_open (exe_filename, NULL);
1304 mono_fixup_exe_image (exe_image);
1305 #endif
1306 } else if (runtime_version != NULL) {
1307 runtimes [0] = get_runtime_by_version (runtime_version);
1308 runtimes [1] = NULL;
1311 if (runtimes [0] == NULL) {
1312 const MonoRuntimeInfo *default_runtime = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
1313 runtimes [0] = default_runtime;
1314 runtimes [1] = NULL;
1315 g_print ("WARNING: The runtime version supported by this application is unavailable.\n");
1316 g_print ("Using default runtime: %s\n", default_runtime->runtime_version);
1319 /* The selected runtime will be the first one for which there is a mscrolib.dll */
1320 for (n = 0; runtimes [n] != NULL && ass == NULL; n++) {
1321 current_runtime = runtimes [n];
1322 ass = mono_assembly_load_corlib (current_runtime, &status);
1323 if (status != MONO_IMAGE_OK && status != MONO_IMAGE_ERROR_ERRNO)
1324 break;
1328 /* Now that we have a runtime, set the policy for unhandled exceptions */
1329 if (mono_framework_version () < 2) {
1330 mono_runtime_unhandled_exception_policy_set (MONO_UNHANDLED_POLICY_LEGACY);
1333 if ((status != MONO_IMAGE_OK) || (ass == NULL)) {
1334 switch (status){
1335 case MONO_IMAGE_ERROR_ERRNO: {
1336 char *corlib_file = g_build_filename (mono_assembly_getrootdir (), "mono", current_runtime->framework_version, "mscorlib.dll", NULL);
1337 g_print ("The assembly mscorlib.dll was not found or could not be loaded.\n");
1338 g_print ("It should have been installed in the `%s' directory.\n", corlib_file);
1339 g_free (corlib_file);
1340 break;
1342 case MONO_IMAGE_IMAGE_INVALID:
1343 g_print ("The file %s/mscorlib.dll is an invalid CIL image\n",
1344 mono_assembly_getrootdir ());
1345 break;
1346 case MONO_IMAGE_MISSING_ASSEMBLYREF:
1347 g_print ("Missing assembly reference in %s/mscorlib.dll\n",
1348 mono_assembly_getrootdir ());
1349 break;
1350 case MONO_IMAGE_OK:
1351 /* to suppress compiler warning */
1352 break;
1355 exit (1);
1357 mono_defaults.corlib = mono_assembly_get_image (ass);
1359 mono_defaults.object_class = mono_class_from_name (
1360 mono_defaults.corlib, "System", "Object");
1361 g_assert (mono_defaults.object_class != 0);
1363 mono_defaults.void_class = mono_class_from_name (
1364 mono_defaults.corlib, "System", "Void");
1365 g_assert (mono_defaults.void_class != 0);
1367 mono_defaults.boolean_class = mono_class_from_name (
1368 mono_defaults.corlib, "System", "Boolean");
1369 g_assert (mono_defaults.boolean_class != 0);
1371 mono_defaults.byte_class = mono_class_from_name (
1372 mono_defaults.corlib, "System", "Byte");
1373 g_assert (mono_defaults.byte_class != 0);
1375 mono_defaults.sbyte_class = mono_class_from_name (
1376 mono_defaults.corlib, "System", "SByte");
1377 g_assert (mono_defaults.sbyte_class != 0);
1379 mono_defaults.int16_class = mono_class_from_name (
1380 mono_defaults.corlib, "System", "Int16");
1381 g_assert (mono_defaults.int16_class != 0);
1383 mono_defaults.uint16_class = mono_class_from_name (
1384 mono_defaults.corlib, "System", "UInt16");
1385 g_assert (mono_defaults.uint16_class != 0);
1387 mono_defaults.int32_class = mono_class_from_name (
1388 mono_defaults.corlib, "System", "Int32");
1389 g_assert (mono_defaults.int32_class != 0);
1391 mono_defaults.uint32_class = mono_class_from_name (
1392 mono_defaults.corlib, "System", "UInt32");
1393 g_assert (mono_defaults.uint32_class != 0);
1395 mono_defaults.uint_class = mono_class_from_name (
1396 mono_defaults.corlib, "System", "UIntPtr");
1397 g_assert (mono_defaults.uint_class != 0);
1399 mono_defaults.int_class = mono_class_from_name (
1400 mono_defaults.corlib, "System", "IntPtr");
1401 g_assert (mono_defaults.int_class != 0);
1403 mono_defaults.int64_class = mono_class_from_name (
1404 mono_defaults.corlib, "System", "Int64");
1405 g_assert (mono_defaults.int64_class != 0);
1407 mono_defaults.uint64_class = mono_class_from_name (
1408 mono_defaults.corlib, "System", "UInt64");
1409 g_assert (mono_defaults.uint64_class != 0);
1411 mono_defaults.single_class = mono_class_from_name (
1412 mono_defaults.corlib, "System", "Single");
1413 g_assert (mono_defaults.single_class != 0);
1415 mono_defaults.double_class = mono_class_from_name (
1416 mono_defaults.corlib, "System", "Double");
1417 g_assert (mono_defaults.double_class != 0);
1419 mono_defaults.char_class = mono_class_from_name (
1420 mono_defaults.corlib, "System", "Char");
1421 g_assert (mono_defaults.char_class != 0);
1423 mono_defaults.string_class = mono_class_from_name (
1424 mono_defaults.corlib, "System", "String");
1425 g_assert (mono_defaults.string_class != 0);
1427 mono_defaults.enum_class = mono_class_from_name (
1428 mono_defaults.corlib, "System", "Enum");
1429 g_assert (mono_defaults.enum_class != 0);
1431 mono_defaults.array_class = mono_class_from_name (
1432 mono_defaults.corlib, "System", "Array");
1433 g_assert (mono_defaults.array_class != 0);
1435 mono_defaults.delegate_class = mono_class_from_name (
1436 mono_defaults.corlib, "System", "Delegate");
1437 g_assert (mono_defaults.delegate_class != 0 );
1439 mono_defaults.multicastdelegate_class = mono_class_from_name (
1440 mono_defaults.corlib, "System", "MulticastDelegate");
1441 g_assert (mono_defaults.multicastdelegate_class != 0 );
1443 mono_defaults.asyncresult_class = mono_class_from_name (
1444 mono_defaults.corlib, "System.Runtime.Remoting.Messaging",
1445 "AsyncResult");
1446 g_assert (mono_defaults.asyncresult_class != 0 );
1448 mono_defaults.manualresetevent_class = mono_class_from_name (
1449 mono_defaults.corlib, "System.Threading", "ManualResetEvent");
1450 g_assert (mono_defaults.manualresetevent_class != 0 );
1452 mono_defaults.typehandle_class = mono_class_from_name (
1453 mono_defaults.corlib, "System", "RuntimeTypeHandle");
1454 g_assert (mono_defaults.typehandle_class != 0);
1456 mono_defaults.methodhandle_class = mono_class_from_name (
1457 mono_defaults.corlib, "System", "RuntimeMethodHandle");
1458 g_assert (mono_defaults.methodhandle_class != 0);
1460 mono_defaults.fieldhandle_class = mono_class_from_name (
1461 mono_defaults.corlib, "System", "RuntimeFieldHandle");
1462 g_assert (mono_defaults.fieldhandle_class != 0);
1464 mono_defaults.systemtype_class = mono_class_from_name (
1465 mono_defaults.corlib, "System", "Type");
1466 g_assert (mono_defaults.systemtype_class != 0);
1468 mono_defaults.monotype_class = mono_class_from_name (
1469 mono_defaults.corlib, "System", "MonoType");
1470 g_assert (mono_defaults.monotype_class != 0);
1472 mono_defaults.exception_class = mono_class_from_name (
1473 mono_defaults.corlib, "System", "Exception");
1474 g_assert (mono_defaults.exception_class != 0);
1476 mono_defaults.threadabortexception_class = mono_class_from_name (
1477 mono_defaults.corlib, "System.Threading", "ThreadAbortException");
1478 g_assert (mono_defaults.threadabortexception_class != 0);
1480 mono_defaults.thread_class = mono_class_from_name (
1481 mono_defaults.corlib, "System.Threading", "Thread");
1482 g_assert (mono_defaults.thread_class != 0);
1484 mono_defaults.internal_thread_class = mono_class_from_name (
1485 mono_defaults.corlib, "System.Threading", "InternalThread");
1486 if (!mono_defaults.internal_thread_class) {
1487 /* This can happen with an old mscorlib */
1488 fprintf (stderr, "Corlib too old for this runtime.\n");
1489 fprintf (stderr, "Loaded from: %s\n",
1490 mono_defaults.corlib? mono_image_get_filename (mono_defaults.corlib): "unknown");
1491 exit (1);
1494 mono_defaults.appdomain_class = mono_class_from_name (
1495 mono_defaults.corlib, "System", "AppDomain");
1496 g_assert (mono_defaults.appdomain_class != 0);
1498 mono_defaults.transparent_proxy_class = mono_class_from_name (
1499 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "TransparentProxy");
1500 g_assert (mono_defaults.transparent_proxy_class != 0);
1502 mono_defaults.real_proxy_class = mono_class_from_name (
1503 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "RealProxy");
1504 g_assert (mono_defaults.real_proxy_class != 0);
1506 mono_defaults.mono_method_message_class = mono_class_from_name (
1507 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", "MonoMethodMessage");
1508 g_assert (mono_defaults.mono_method_message_class != 0);
1510 mono_defaults.field_info_class = mono_class_from_name (
1511 mono_defaults.corlib, "System.Reflection", "FieldInfo");
1512 g_assert (mono_defaults.field_info_class != 0);
1514 mono_defaults.method_info_class = mono_class_from_name (
1515 mono_defaults.corlib, "System.Reflection", "MethodInfo");
1516 g_assert (mono_defaults.method_info_class != 0);
1518 mono_defaults.stringbuilder_class = mono_class_from_name (
1519 mono_defaults.corlib, "System.Text", "StringBuilder");
1520 g_assert (mono_defaults.stringbuilder_class != 0);
1522 mono_defaults.math_class = mono_class_from_name (
1523 mono_defaults.corlib, "System", "Math");
1524 g_assert (mono_defaults.math_class != 0);
1526 mono_defaults.stack_frame_class = mono_class_from_name (
1527 mono_defaults.corlib, "System.Diagnostics", "StackFrame");
1528 g_assert (mono_defaults.stack_frame_class != 0);
1530 mono_defaults.stack_trace_class = mono_class_from_name (
1531 mono_defaults.corlib, "System.Diagnostics", "StackTrace");
1532 g_assert (mono_defaults.stack_trace_class != 0);
1534 mono_defaults.marshal_class = mono_class_from_name (
1535 mono_defaults.corlib, "System.Runtime.InteropServices", "Marshal");
1536 g_assert (mono_defaults.marshal_class != 0);
1538 mono_defaults.iserializeable_class = mono_class_from_name (
1539 mono_defaults.corlib, "System.Runtime.Serialization", "ISerializable");
1540 g_assert (mono_defaults.iserializeable_class != 0);
1542 mono_defaults.serializationinfo_class = mono_class_from_name (
1543 mono_defaults.corlib, "System.Runtime.Serialization", "SerializationInfo");
1544 g_assert (mono_defaults.serializationinfo_class != 0);
1546 mono_defaults.streamingcontext_class = mono_class_from_name (
1547 mono_defaults.corlib, "System.Runtime.Serialization", "StreamingContext");
1548 g_assert (mono_defaults.streamingcontext_class != 0);
1550 mono_defaults.typed_reference_class = mono_class_from_name (
1551 mono_defaults.corlib, "System", "TypedReference");
1552 g_assert (mono_defaults.typed_reference_class != 0);
1554 mono_defaults.argumenthandle_class = mono_class_from_name (
1555 mono_defaults.corlib, "System", "RuntimeArgumentHandle");
1556 g_assert (mono_defaults.argumenthandle_class != 0);
1558 mono_defaults.marshalbyrefobject_class = mono_class_from_name (
1559 mono_defaults.corlib, "System", "MarshalByRefObject");
1560 g_assert (mono_defaults.marshalbyrefobject_class != 0);
1562 mono_defaults.monitor_class = mono_class_from_name (
1563 mono_defaults.corlib, "System.Threading", "Monitor");
1564 g_assert (mono_defaults.monitor_class != 0);
1566 mono_defaults.iremotingtypeinfo_class = mono_class_from_name (
1567 mono_defaults.corlib, "System.Runtime.Remoting", "IRemotingTypeInfo");
1568 g_assert (mono_defaults.iremotingtypeinfo_class != 0);
1570 mono_defaults.runtimesecurityframe_class = mono_class_from_name (
1571 mono_defaults.corlib, "System.Security", "RuntimeSecurityFrame");
1573 mono_defaults.executioncontext_class = mono_class_from_name (
1574 mono_defaults.corlib, "System.Threading", "ExecutionContext");
1576 mono_defaults.internals_visible_class = mono_class_from_name (
1577 mono_defaults.corlib, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute");
1579 mono_defaults.critical_finalizer_object = mono_class_from_name (
1580 mono_defaults.corlib, "System.Runtime.ConstrainedExecution", "CriticalFinalizerObject");
1583 * mscorlib needs a little help, only now it can load its friends list (after we have
1584 * loaded the InternalsVisibleToAttribute), load it now
1586 mono_assembly_load_friends (ass);
1588 mono_defaults.safehandle_class = mono_class_from_name (
1589 mono_defaults.corlib, "System.Runtime.InteropServices", "SafeHandle");
1591 mono_defaults.handleref_class = mono_class_from_name (
1592 mono_defaults.corlib, "System.Runtime.InteropServices", "HandleRef");
1594 mono_defaults.attribute_class = mono_class_from_name (
1595 mono_defaults.corlib, "System", "Attribute");
1597 mono_defaults.customattribute_data_class = mono_class_from_name (
1598 mono_defaults.corlib, "System.Reflection", "CustomAttributeData");
1600 /* these are initialized lazily when COM features are used */
1601 mono_defaults.variant_class = NULL;
1602 mono_defaults.com_object_class = NULL;
1603 mono_defaults.com_interop_proxy_class = NULL;
1604 mono_defaults.iunknown_class = NULL;
1605 mono_defaults.idispatch_class = NULL;
1608 * Note that mono_defaults.generic_*_class is only non-NULL if we're
1609 * using the 2.0 corlib.
1611 mono_class_init (mono_defaults.array_class);
1612 mono_defaults.generic_nullable_class = mono_class_from_name (
1613 mono_defaults.corlib, "System", "Nullable`1");
1614 mono_defaults.generic_ilist_class = mono_class_from_name (
1615 mono_defaults.corlib, "System.Collections.Generic", "IList`1");
1617 domain->friendly_name = g_path_get_basename (filename);
1619 _mono_debug_init_corlib (domain);
1621 return domain;
1625 * mono_init:
1627 * Creates the initial application domain and initializes the mono_defaults
1628 * structure.
1629 * This function is guaranteed to not run any IL code.
1630 * The runtime is initialized using the default runtime version.
1632 * Returns: the initial domain.
1634 MonoDomain *
1635 mono_init (const char *domain_name)
1637 return mono_init_internal (domain_name, NULL, DEFAULT_RUNTIME_VERSION);
1641 * mono_init_from_assembly:
1643 * Creates the initial application domain and initializes the mono_defaults
1644 * structure.
1645 * This function is guaranteed to not run any IL code.
1646 * The runtime is initialized using the runtime version required by the
1647 * provided executable. The version is determined by looking at the exe
1648 * configuration file and the version PE field)
1650 * Returns: the initial domain.
1652 MonoDomain *
1653 mono_init_from_assembly (const char *domain_name, const char *filename)
1655 return mono_init_internal (domain_name, filename, NULL);
1659 * mono_init_version:
1661 * Creates the initial application domain and initializes the mono_defaults
1662 * structure.
1663 * This function is guaranteed to not run any IL code.
1664 * The runtime is initialized using the provided rutime version.
1666 * Returns: the initial domain.
1668 MonoDomain *
1669 mono_init_version (const char *domain_name, const char *version)
1671 return mono_init_internal (domain_name, NULL, version);
1675 * mono_init_com_types:
1677 * Initializes all types needed for COM Interop in mono_defaults structure.
1679 void
1680 mono_init_com_types (void)
1682 static gboolean initialized = FALSE;
1684 if (initialized)
1685 return;
1687 /* FIXME: do I need some threading protection here */
1689 g_assert (mono_defaults.corlib);
1691 mono_defaults.variant_class = mono_class_from_name (
1692 mono_defaults.corlib, "System", "Variant");
1693 g_assert (mono_defaults.variant_class != 0);
1695 mono_defaults.com_object_class = mono_class_from_name (
1696 mono_defaults.corlib, "System", "__ComObject");
1697 g_assert (mono_defaults.com_object_class != 0);
1699 mono_defaults.com_interop_proxy_class = mono_class_from_name (
1700 mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
1701 g_assert (mono_defaults.com_interop_proxy_class != 0);
1703 mono_defaults.iunknown_class = mono_class_from_name (
1704 mono_defaults.corlib, "Mono.Interop", "IUnknown");
1705 g_assert (mono_defaults.iunknown_class != 0);
1707 mono_defaults.idispatch_class = mono_class_from_name (
1708 mono_defaults.corlib, "Mono.Interop", "IDispatch");
1709 g_assert (mono_defaults.idispatch_class != 0);
1711 initialized = TRUE;
1715 * mono_cleanup:
1717 * Cleans up all metadata modules.
1719 void
1720 mono_cleanup (void)
1722 mono_close_exe_image ();
1724 mono_loader_cleanup ();
1725 mono_classes_cleanup ();
1726 mono_assemblies_cleanup ();
1727 mono_images_cleanup ();
1728 mono_debug_cleanup ();
1729 mono_metadata_cleanup ();
1731 TlsFree (appdomain_thread_id);
1732 DeleteCriticalSection (&appdomains_mutex);
1735 void
1736 mono_close_exe_image (void)
1738 if (exe_image)
1739 mono_image_close (exe_image);
1743 * mono_get_root_domain:
1745 * The root AppDomain is the initial domain created by the runtime when it is
1746 * initialized. Programs execute on this AppDomain, but can create new ones
1747 * later. Currently there is no unmanaged API to create new AppDomains, this
1748 * must be done from managed code.
1750 * Returns: the root appdomain, to obtain the current domain, use mono_domain_get ()
1752 MonoDomain*
1753 mono_get_root_domain (void)
1755 return mono_root_domain;
1759 * mono_domain_get:
1761 * Returns: the current domain, to obtain the root domain use
1762 * mono_get_root_domain().
1764 MonoDomain *
1765 mono_domain_get ()
1767 return GET_APPDOMAIN ();
1770 void
1771 mono_domain_set_internal_with_options (MonoDomain *domain, gboolean migrate_exception)
1773 MonoInternalThread *thread;
1775 if (mono_domain_get () == domain)
1776 return;
1778 SET_APPDOMAIN (domain);
1779 SET_APPCONTEXT (domain->default_context);
1781 if (migrate_exception) {
1782 thread = mono_thread_internal_current ();
1783 if (!thread->abort_exc)
1784 return;
1786 g_assert (thread->abort_exc->object.vtable->domain != domain);
1787 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
1788 g_assert (thread->abort_exc->object.vtable->domain == domain);
1793 * mono_domain_set_internal:
1794 * @domain: the new domain
1796 * Sets the current domain to @domain.
1798 void
1799 mono_domain_set_internal (MonoDomain *domain)
1801 mono_domain_set_internal_with_options (domain, TRUE);
1804 void
1805 mono_domain_foreach (MonoDomainFunc func, gpointer user_data)
1807 int i, size;
1808 MonoDomain **copy;
1811 * Create a copy of the data to avoid calling the user callback
1812 * inside the lock because that could lead to deadlocks.
1813 * We can do this because this function is not perf. critical.
1815 mono_appdomains_lock ();
1816 size = appdomain_list_size;
1817 copy = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1818 memcpy (copy, appdomains_list, appdomain_list_size * sizeof (void*));
1819 mono_appdomains_unlock ();
1821 for (i = 0; i < size; ++i) {
1822 if (copy [i])
1823 func (copy [i], user_data);
1826 mono_gc_free_fixed (copy);
1830 * mono_domain_assembly_open:
1831 * @domain: the application domain
1832 * @name: file name of the assembly
1834 * fixme: maybe we should integrate this with mono_assembly_open ??
1836 MonoAssembly *
1837 mono_domain_assembly_open (MonoDomain *domain, const char *name)
1839 MonoDomain *current;
1840 MonoAssembly *ass;
1841 GSList *tmp;
1843 mono_domain_assemblies_lock (domain);
1844 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1845 ass = tmp->data;
1846 if (strcmp (name, ass->aname.name) == 0) {
1847 mono_domain_assemblies_unlock (domain);
1848 return ass;
1851 mono_domain_assemblies_unlock (domain);
1853 if (domain != mono_domain_get ()) {
1854 current = mono_domain_get ();
1856 mono_domain_set (domain, FALSE);
1857 ass = mono_assembly_open (name, NULL);
1858 mono_domain_set (current, FALSE);
1859 } else {
1860 ass = mono_assembly_open (name, NULL);
1863 return ass;
1866 static void
1867 free_slist (gpointer key, gpointer value, gpointer user_data)
1869 g_slist_free (value);
1872 void
1873 mono_domain_free (MonoDomain *domain, gboolean force)
1875 int code_size, code_alloc;
1876 GSList *tmp;
1877 if ((domain == mono_root_domain) && !force) {
1878 g_warning ("cant unload root domain");
1879 return;
1882 if (mono_dont_free_domains)
1883 return;
1885 mono_profiler_appdomain_event (domain, MONO_PROFILE_START_UNLOAD);
1887 if (free_domain_hook)
1888 free_domain_hook (domain);
1890 mono_debug_domain_unload (domain);
1892 mono_appdomains_lock ();
1893 appdomains_list [domain->domain_id] = NULL;
1894 mono_appdomains_unlock ();
1896 /* must do this early as it accesses fields and types */
1897 if (domain->special_static_fields) {
1898 mono_alloc_special_static_data_free (domain->special_static_fields);
1899 g_hash_table_destroy (domain->special_static_fields);
1900 domain->special_static_fields = NULL;
1904 * We must destroy all these hash tables here because they
1905 * contain references to managed objects belonging to the
1906 * domain. Once we let the GC clear the domain there must be
1907 * no more such references, or we'll crash if a collection
1908 * occurs.
1910 mono_g_hash_table_destroy (domain->ldstr_table);
1911 domain->ldstr_table = NULL;
1913 mono_g_hash_table_destroy (domain->env);
1914 domain->env = NULL;
1916 mono_reflection_cleanup_domain (domain);
1918 if (domain->type_hash) {
1919 mono_g_hash_table_destroy (domain->type_hash);
1920 domain->type_hash = NULL;
1922 if (domain->type_init_exception_hash) {
1923 mono_g_hash_table_destroy (domain->type_init_exception_hash);
1924 domain->type_init_exception_hash = NULL;
1927 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1928 MonoAssembly *ass = tmp->data;
1929 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);
1930 if (!mono_assembly_close_except_image_pools (ass))
1931 tmp->data = NULL;
1934 mono_gc_clear_domain (domain);
1936 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1937 MonoAssembly *ass = tmp->data;
1938 if (ass)
1939 mono_assembly_close_finish (ass);
1941 g_slist_free (domain->domain_assemblies);
1942 domain->domain_assemblies = NULL;
1944 /* FIXME: free delegate_hash_table when it's used */
1945 if (domain->search_path) {
1946 g_strfreev (domain->search_path);
1947 domain->search_path = NULL;
1949 domain->create_proxy_for_type_method = NULL;
1950 domain->private_invoke_method = NULL;
1951 domain->default_context = NULL;
1952 domain->out_of_memory_ex = NULL;
1953 domain->null_reference_ex = NULL;
1954 domain->stack_overflow_ex = NULL;
1955 domain->entry_assembly = NULL;
1957 g_free (domain->friendly_name);
1958 domain->friendly_name = NULL;
1959 g_hash_table_destroy (domain->class_vtable_hash);
1960 domain->class_vtable_hash = NULL;
1961 g_hash_table_destroy (domain->proxy_vtable_hash);
1962 domain->proxy_vtable_hash = NULL;
1963 if (domain->static_data_array) {
1964 mono_gc_free_fixed (domain->static_data_array);
1965 domain->static_data_array = NULL;
1967 mono_internal_hash_table_destroy (&domain->jit_code_hash);
1970 * There might still be jit info tables of this domain which
1971 * are not freed. Since the domain cannot be in use anymore,
1972 * this will free them.
1974 mono_thread_hazardous_try_free_all ();
1975 g_assert (domain->num_jit_info_tables == 1);
1976 jit_info_table_free (domain->jit_info_table);
1977 domain->jit_info_table = NULL;
1978 g_assert (!domain->jit_info_free_queue);
1980 /* collect statistics */
1981 code_alloc = mono_code_manager_size (domain->code_mp, &code_size);
1982 total_domain_code_alloc += code_alloc;
1983 max_domain_code_alloc = MAX (max_domain_code_alloc, code_alloc);
1984 max_domain_code_size = MAX (max_domain_code_size, code_size);
1986 #ifdef DEBUG_DOMAIN_UNLOAD
1987 mono_mempool_invalidate (domain->mp);
1988 mono_code_manager_invalidate (domain->code_mp);
1989 #else
1990 mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (domain->mp);
1991 mono_mempool_destroy (domain->mp);
1992 domain->mp = NULL;
1993 mono_code_manager_destroy (domain->code_mp);
1994 domain->code_mp = NULL;
1995 #endif
1997 g_hash_table_destroy (domain->finalizable_objects_hash);
1998 domain->finalizable_objects_hash = NULL;
1999 #ifndef HAVE_SGEN_GC
2000 if (domain->track_resurrection_objects_hash) {
2001 g_hash_table_foreach (domain->track_resurrection_objects_hash, free_slist, NULL);
2002 g_hash_table_destroy (domain->track_resurrection_objects_hash);
2004 if (domain->track_resurrection_handles_hash)
2005 g_hash_table_destroy (domain->track_resurrection_handles_hash);
2006 #endif
2007 if (domain->method_rgctx_hash) {
2008 g_hash_table_destroy (domain->method_rgctx_hash);
2009 domain->method_rgctx_hash = NULL;
2011 if (domain->generic_virtual_cases) {
2012 g_hash_table_destroy (domain->generic_virtual_cases);
2013 domain->generic_virtual_cases = NULL;
2016 DeleteCriticalSection (&domain->finalizable_objects_hash_lock);
2017 DeleteCriticalSection (&domain->assemblies_lock);
2018 DeleteCriticalSection (&domain->jit_code_hash_lock);
2019 DeleteCriticalSection (&domain->lock);
2020 domain->setup = NULL;
2022 mono_gc_deregister_root ((char*)&(domain->MONO_DOMAIN_FIRST_GC_TRACKED));
2024 /* FIXME: anything else required ? */
2026 mono_profiler_appdomain_event (domain, MONO_PROFILE_END_UNLOAD);
2028 mono_gc_free_fixed (domain);
2030 mono_perfcounters->loader_appdomains--;
2032 if ((domain == mono_root_domain))
2033 mono_root_domain = NULL;
2037 * mono_domain_get_id:
2038 * @domainid: the ID
2040 * Returns: the a domain for a specific domain id.
2042 MonoDomain *
2043 mono_domain_get_by_id (gint32 domainid)
2045 MonoDomain * domain;
2047 mono_appdomains_lock ();
2048 if (domainid < appdomain_list_size)
2049 domain = appdomains_list [domainid];
2050 else
2051 domain = NULL;
2052 mono_appdomains_unlock ();
2054 return domain;
2057 gint32
2058 mono_domain_get_id (MonoDomain *domain)
2060 return domain->domain_id;
2064 * mono_domain_alloc:
2066 * LOCKING: Acquires the domain lock.
2068 gpointer
2069 mono_domain_alloc (MonoDomain *domain, guint size)
2071 gpointer res;
2073 mono_domain_lock (domain);
2074 mono_perfcounters->loader_bytes += size;
2075 res = mono_mempool_alloc (domain->mp, size);
2076 mono_domain_unlock (domain);
2078 return res;
2082 * mono_domain_alloc0:
2084 * LOCKING: Acquires the domain lock.
2086 gpointer
2087 mono_domain_alloc0 (MonoDomain *domain, guint size)
2089 gpointer res;
2091 mono_domain_lock (domain);
2092 mono_perfcounters->loader_bytes += size;
2093 res = mono_mempool_alloc0 (domain->mp, size);
2094 mono_domain_unlock (domain);
2096 return res;
2100 * mono_domain_code_reserve:
2102 * LOCKING: Acquires the domain lock.
2104 void*
2105 mono_domain_code_reserve (MonoDomain *domain, int size)
2107 gpointer res;
2109 mono_domain_lock (domain);
2110 res = mono_code_manager_reserve (domain->code_mp, size);
2111 mono_domain_unlock (domain);
2113 return res;
2117 * mono_domain_code_reserve_align:
2119 * LOCKING: Acquires the domain lock.
2121 void*
2122 mono_domain_code_reserve_align (MonoDomain *domain, int size, int alignment)
2124 gpointer res;
2126 mono_domain_lock (domain);
2127 res = mono_code_manager_reserve_align (domain->code_mp, size, alignment);
2128 mono_domain_unlock (domain);
2130 return res;
2134 * mono_domain_code_commit:
2136 * LOCKING: Acquires the domain lock.
2138 void
2139 mono_domain_code_commit (MonoDomain *domain, void *data, int size, int newsize)
2141 mono_domain_lock (domain);
2142 mono_code_manager_commit (domain->code_mp, data, size, newsize);
2143 mono_domain_unlock (domain);
2147 * mono_domain_code_foreach:
2148 * Iterate over the code thunks of the code manager of @domain.
2150 * The @func callback MUST not take any locks. If it really needs to, it must respect
2151 * the locking rules of the runtime: http://www.mono-project.com/Mono:Runtime:Documentation:ThreadSafety
2152 * LOCKING: Acquires the domain lock.
2155 void
2156 mono_domain_code_foreach (MonoDomain *domain, MonoCodeManagerFunc func, void *user_data)
2158 mono_domain_lock (domain);
2159 mono_code_manager_foreach (domain->code_mp, func, user_data);
2160 mono_domain_unlock (domain);
2164 void
2165 mono_context_set (MonoAppContext * new_context)
2167 SET_APPCONTEXT (new_context);
2170 MonoAppContext *
2171 mono_context_get (void)
2173 return GET_APPCONTEXT ();
2176 /* LOCKING: the caller holds the lock for this domain */
2177 void
2178 mono_domain_add_class_static_data (MonoDomain *domain, MonoClass *klass, gpointer data, guint32 *bitmap)
2180 /* The first entry in the array is the index of the next free slot
2181 * and the total size of the array
2183 int next;
2184 if (domain->static_data_array) {
2185 int size = GPOINTER_TO_INT (domain->static_data_array [1]);
2186 next = GPOINTER_TO_INT (domain->static_data_array [0]);
2187 if (next >= size) {
2188 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * (size * 2), NULL);
2189 memcpy (new_array, domain->static_data_array, sizeof (gpointer) * size);
2190 size *= 2;
2191 new_array [1] = GINT_TO_POINTER (size);
2192 mono_gc_free_fixed (domain->static_data_array);
2193 domain->static_data_array = new_array;
2195 } else {
2196 int size = 32;
2197 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * size, NULL);
2198 next = 2;
2199 new_array [0] = GINT_TO_POINTER (next);
2200 new_array [1] = GINT_TO_POINTER (size);
2201 domain->static_data_array = new_array;
2203 domain->static_data_array [next++] = data;
2204 domain->static_data_array [0] = GINT_TO_POINTER (next);
2207 MonoImage*
2208 mono_get_corlib (void)
2210 return mono_defaults.corlib;
2213 MonoClass*
2214 mono_get_object_class (void)
2216 return mono_defaults.object_class;
2219 MonoClass*
2220 mono_get_byte_class (void)
2222 return mono_defaults.byte_class;
2225 MonoClass*
2226 mono_get_void_class (void)
2228 return mono_defaults.void_class;
2231 MonoClass*
2232 mono_get_boolean_class (void)
2234 return mono_defaults.boolean_class;
2237 MonoClass*
2238 mono_get_sbyte_class (void)
2240 return mono_defaults.sbyte_class;
2243 MonoClass*
2244 mono_get_int16_class (void)
2246 return mono_defaults.int16_class;
2249 MonoClass*
2250 mono_get_uint16_class (void)
2252 return mono_defaults.uint16_class;
2255 MonoClass*
2256 mono_get_int32_class (void)
2258 return mono_defaults.int32_class;
2261 MonoClass*
2262 mono_get_uint32_class (void)
2264 return mono_defaults.uint32_class;
2267 MonoClass*
2268 mono_get_intptr_class (void)
2270 return mono_defaults.int_class;
2273 MonoClass*
2274 mono_get_uintptr_class (void)
2276 return mono_defaults.uint_class;
2279 MonoClass*
2280 mono_get_int64_class (void)
2282 return mono_defaults.int64_class;
2285 MonoClass*
2286 mono_get_uint64_class (void)
2288 return mono_defaults.uint64_class;
2291 MonoClass*
2292 mono_get_single_class (void)
2294 return mono_defaults.single_class;
2297 MonoClass*
2298 mono_get_double_class (void)
2300 return mono_defaults.double_class;
2303 MonoClass*
2304 mono_get_char_class (void)
2306 return mono_defaults.char_class;
2309 MonoClass*
2310 mono_get_string_class (void)
2312 return mono_defaults.string_class;
2315 MonoClass*
2316 mono_get_enum_class (void)
2318 return mono_defaults.enum_class;
2321 MonoClass*
2322 mono_get_array_class (void)
2324 return mono_defaults.array_class;
2327 MonoClass*
2328 mono_get_thread_class (void)
2330 return mono_defaults.thread_class;
2333 MonoClass*
2334 mono_get_exception_class (void)
2336 return mono_defaults.exception_class;
2340 static char* get_attribute_value (const gchar **attribute_names,
2341 const gchar **attribute_values,
2342 const char *att_name)
2344 int n;
2345 for (n=0; attribute_names[n] != NULL; n++) {
2346 if (strcmp (attribute_names[n], att_name) == 0)
2347 return g_strdup (attribute_values[n]);
2349 return NULL;
2352 static void start_element (GMarkupParseContext *context,
2353 const gchar *element_name,
2354 const gchar **attribute_names,
2355 const gchar **attribute_values,
2356 gpointer user_data,
2357 GError **error)
2359 AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2361 if (strcmp (element_name, "configuration") == 0) {
2362 app_config->configuration_count++;
2363 return;
2365 if (strcmp (element_name, "startup") == 0) {
2366 app_config->startup_count++;
2367 return;
2370 if (app_config->configuration_count != 1 || app_config->startup_count != 1)
2371 return;
2373 if (strcmp (element_name, "requiredRuntime") == 0) {
2374 app_config->required_runtime = get_attribute_value (attribute_names, attribute_values, "version");
2375 } else if (strcmp (element_name, "supportedRuntime") == 0) {
2376 char *version = get_attribute_value (attribute_names, attribute_values, "version");
2377 app_config->supported_runtimes = g_slist_append (app_config->supported_runtimes, version);
2381 static void end_element (GMarkupParseContext *context,
2382 const gchar *element_name,
2383 gpointer user_data,
2384 GError **error)
2386 AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2388 if (strcmp (element_name, "configuration") == 0) {
2389 app_config->configuration_count--;
2390 } else if (strcmp (element_name, "startup") == 0) {
2391 app_config->startup_count--;
2395 static const GMarkupParser
2396 mono_parser = {
2397 start_element,
2398 end_element,
2399 NULL,
2400 NULL,
2401 NULL
2404 static AppConfigInfo *
2405 app_config_parse (const char *exe_filename)
2407 AppConfigInfo *app_config;
2408 GMarkupParseContext *context;
2409 char *text;
2410 gsize len;
2411 const char *bundled_config;
2412 char *config_filename;
2414 bundled_config = mono_config_string_for_assembly_file (exe_filename);
2416 if (bundled_config) {
2417 text = g_strdup (bundled_config);
2418 len = strlen (text);
2419 } else {
2420 config_filename = g_strconcat (exe_filename, ".config", NULL);
2422 if (!g_file_get_contents (config_filename, &text, &len, NULL)) {
2423 g_free (config_filename);
2424 return NULL;
2426 g_free (config_filename);
2429 app_config = g_new0 (AppConfigInfo, 1);
2431 context = g_markup_parse_context_new (&mono_parser, 0, app_config, NULL);
2432 if (g_markup_parse_context_parse (context, text, len, NULL)) {
2433 g_markup_parse_context_end_parse (context, NULL);
2435 g_markup_parse_context_free (context);
2436 g_free (text);
2437 return app_config;
2440 static void
2441 app_config_free (AppConfigInfo* app_config)
2443 char *rt;
2444 GSList *list = app_config->supported_runtimes;
2445 while (list != NULL) {
2446 rt = (char*)list->data;
2447 g_free (rt);
2448 list = g_slist_next (list);
2450 g_slist_free (app_config->supported_runtimes);
2451 g_free (app_config->required_runtime);
2452 g_free (app_config);
2456 static const MonoRuntimeInfo*
2457 get_runtime_by_version (const char *version)
2459 int n;
2460 int max = G_N_ELEMENTS (supported_runtimes);
2462 for (n=0; n<max; n++) {
2463 if (strcmp (version, supported_runtimes[n].runtime_version) == 0)
2464 return &supported_runtimes[n];
2466 return NULL;
2469 static void
2470 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes)
2472 AppConfigInfo* app_config;
2473 char *version;
2474 const MonoRuntimeInfo* runtime = NULL;
2475 MonoImage *image = NULL;
2477 app_config = app_config_parse (exe_file);
2479 if (app_config != NULL) {
2480 /* Check supportedRuntime elements, if none is supported, fail.
2481 * If there are no such elements, look for a requiredRuntime element.
2483 if (app_config->supported_runtimes != NULL) {
2484 int n = 0;
2485 GSList *list = app_config->supported_runtimes;
2486 while (list != NULL) {
2487 version = (char*) list->data;
2488 runtime = get_runtime_by_version (version);
2489 if (runtime != NULL)
2490 runtimes [n++] = runtime;
2491 list = g_slist_next (list);
2493 runtimes [n] = NULL;
2494 app_config_free (app_config);
2495 return;
2498 /* Check the requiredRuntime element. This is for 1.0 apps only. */
2499 if (app_config->required_runtime != NULL) {
2500 runtimes [0] = get_runtime_by_version (app_config->required_runtime);
2501 runtimes [1] = NULL;
2502 app_config_free (app_config);
2503 return;
2505 app_config_free (app_config);
2508 /* Look for a runtime with the exact version */
2509 image = mono_assembly_open_from_bundle (exe_file, NULL, FALSE);
2511 if (image == NULL)
2512 image = mono_image_open (exe_file, NULL);
2514 if (image == NULL) {
2515 /* The image is wrong or the file was not found. In this case return
2516 * a default runtime and leave to the initialization method the work of
2517 * reporting the error.
2519 runtimes [0] = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
2520 runtimes [1] = NULL;
2521 return;
2524 *exe_image = image;
2526 runtimes [0] = get_runtime_by_version (image->version);
2527 runtimes [1] = NULL;
2532 * mono_get_runtime_info:
2534 * Returns: the version of the current runtime instance.
2536 const MonoRuntimeInfo*
2537 mono_get_runtime_info (void)
2539 return current_runtime;
2542 gchar *
2543 mono_debugger_check_runtime_version (const char *filename)
2545 const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
2546 const MonoRuntimeInfo *rinfo;
2547 MonoImage *image;
2549 get_runtimes_from_exe (filename, &image, runtimes);
2550 rinfo = runtimes [0];
2552 if (!rinfo)
2553 return g_strdup_printf ("Cannot get runtime version from assembly `%s'", filename);
2555 if (rinfo != current_runtime)
2556 return g_strdup_printf ("The Mono Debugger is currently using the `%s' runtime, but "
2557 "the assembly `%s' requires version `%s'", current_runtime->runtime_version,
2558 filename, rinfo->runtime_version);
2560 return NULL;
2564 * mono_framework_version:
2566 * Return the major version of the framework curently executing.
2569 mono_framework_version (void)
2571 return current_runtime->framework_version [0] - '0';