Merge pull request #649 from DavidS/feature/implement-additional-reference-path
[mono.git] / mono / metadata / domain.c
1 /*
2  * domain.c: MonoDomain functions
3  *
4  * Author:
5  *      Dietmar Maurer (dietmar@ximian.com)
6  *      Patrik Torstensson
7  *
8  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
10  * Copyright 2011-2012 Xamarin, Inc (http://www.xamarin.com)
11  */
12
13 #include <config.h>
14 #include <glib.h>
15 #include <string.h>
16 #include <sys/stat.h>
17
18 #include <mono/metadata/gc-internal.h>
19
20 #include <mono/utils/mono-compiler.h>
21 #include <mono/utils/mono-logger-internal.h>
22 #include <mono/utils/mono-membar.h>
23 #include <mono/utils/mono-counters.h>
24 #include <mono/utils/hazard-pointer.h>
25 #include <mono/utils/mono-tls.h>
26 #include <mono/metadata/object.h>
27 #include <mono/metadata/object-internals.h>
28 #include <mono/metadata/domain-internals.h>
29 #include <mono/metadata/class-internals.h>
30 #include <mono/metadata/assembly.h>
31 #include <mono/metadata/exception.h>
32 #include <mono/metadata/metadata-internals.h>
33 #include <mono/metadata/gc-internal.h>
34 #include <mono/metadata/appdomain.h>
35 #include <mono/metadata/mono-debug-debugger.h>
36 #include <mono/metadata/mono-config.h>
37 #include <mono/metadata/threads-types.h>
38 #include <mono/metadata/runtime.h>
39 #include <metadata/threads.h>
40 #include <metadata/profiler-private.h>
41 #include <mono/metadata/coree.h>
42
43 /* #define DEBUG_DOMAIN_UNLOAD */
44
45 /* we need to use both the Tls* functions and __thread because
46  * some archs may generate faster jit code with one meachanism
47  * or the other (we used to do it because tls slots were GC-tracked,
48  * but we can't depend on this).
49  */
50 static MonoNativeTlsKey appdomain_thread_id;
51
52 #ifdef MONO_HAVE_FAST_TLS
53
54 MONO_FAST_TLS_DECLARE(tls_appdomain);
55
56 #define GET_APPDOMAIN() ((MonoDomain*)MONO_FAST_TLS_GET(tls_appdomain))
57
58 #define SET_APPDOMAIN(x) do { \
59         MONO_FAST_TLS_SET (tls_appdomain,x); \
60         mono_native_tls_set_value (appdomain_thread_id, x); \
61         mono_gc_set_current_thread_appdomain (x); \
62 } while (FALSE)
63
64 #else /* !MONO_HAVE_FAST_TLS */
65
66 #define GET_APPDOMAIN() ((MonoDomain *)mono_native_tls_get_value (appdomain_thread_id))
67 #define SET_APPDOMAIN(x) do {                                           \
68                 mono_native_tls_set_value (appdomain_thread_id, x);     \
69                 mono_gc_set_current_thread_appdomain (x);               \
70         } while (FALSE)
71
72 #endif
73
74 #define GET_APPCONTEXT() (mono_thread_internal_current ()->current_appcontext)
75 #define SET_APPCONTEXT(x) MONO_OBJECT_SETREF (mono_thread_internal_current (), current_appcontext, (x))
76
77 static guint16 appdomain_list_size = 0;
78 static guint16 appdomain_next = 0;
79 static MonoDomain **appdomains_list = NULL;
80 static MonoImage *exe_image;
81
82 gboolean mono_dont_free_domains;
83
84 #define mono_appdomains_lock() EnterCriticalSection (&appdomains_mutex)
85 #define mono_appdomains_unlock() LeaveCriticalSection (&appdomains_mutex)
86 static CRITICAL_SECTION appdomains_mutex;
87
88 static MonoDomain *mono_root_domain = NULL;
89
90 /* some statistics */
91 static int max_domain_code_size = 0;
92 static int max_domain_code_alloc = 0;
93 static int total_domain_code_alloc = 0;
94
95 /* AppConfigInfo: Information about runtime versions supported by an 
96  * aplication.
97  */
98 typedef struct {
99         GSList *supported_runtimes;
100         char *required_runtime;
101         int configuration_count;
102         int startup_count;
103 } AppConfigInfo;
104
105 /*
106  * AotModuleInfo: Contains information about AOT modules.
107  */
108 typedef struct {
109         MonoImage *image;
110         gpointer start, end;
111 } AotModuleInfo;
112
113 static const MonoRuntimeInfo *current_runtime = NULL;
114
115 static MonoJitInfoFindInAot jit_info_find_in_aot_func = NULL;
116
117 /*
118  * Contains information about AOT loaded code.
119  */
120 static MonoAotModuleInfoTable *aot_modules = NULL;
121
122 /* This is the list of runtime versions supported by this JIT.
123  */
124 static const MonoRuntimeInfo supported_runtimes[] = {
125         {"v2.0.50215","2.0", { {2,0,0,0}, { 8,0,0,0}, {3,5,0,0}, {3,0,0,0} } },
126         {"v2.0.50727","2.0", { {2,0,0,0}, { 8,0,0,0}, {3,5,0,0}, {3,0,0,0} } },
127         {"v4.0.30319","4.5", { {4,0,0,0}, {10,0,0,0}, {4,0,0,0}, {4,0,0,0} } },
128         {"v4.0.30128","4.0", { {4,0,0,0}, {10,0,0,0}, {4,0,0,0}, {4,0,0,0} } },
129         {"v4.0.20506","4.0", { {4,0,0,0}, {10,0,0,0}, {4,0,0,0}, {4,0,0,0} } },
130         {"moonlight", "2.1", { {2,0,5,0}, { 9,0,0,0}, {3,5,0,0}, {3,0,0,0} } },
131 };
132
133
134 /* The stable runtime version */
135 #define DEFAULT_RUNTIME_VERSION "v2.0.50727"
136
137 /* Callbacks installed by the JIT */
138 static MonoCreateDomainFunc create_domain_hook;
139 static MonoFreeDomainFunc free_domain_hook;
140
141 /* This is intentionally not in the header file, so people don't misuse it. */
142 extern void _mono_debug_init_corlib (MonoDomain *domain);
143
144 static void
145 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes);
146
147 static const MonoRuntimeInfo*
148 get_runtime_by_version (const char *version);
149
150 static MonoImage*
151 mono_jit_info_find_aot_module (guint8* addr);
152
153 MonoNativeTlsKey
154 mono_domain_get_tls_key (void)
155 {
156         return appdomain_thread_id;
157 }
158
159 gint32
160 mono_domain_get_tls_offset (void)
161 {
162         int offset = -1;
163         MONO_THREAD_VAR_OFFSET (tls_appdomain, offset);
164 /*      __asm ("jmp 1f; .section writetext, \"awx\"; 1: movl $tls_appdomain@ntpoff, %0; jmp 2f; .previous; 2:" 
165                 : "=r" (offset));*/
166         return offset;
167 }
168
169 #define JIT_INFO_TABLE_FILL_RATIO_NOM           3
170 #define JIT_INFO_TABLE_FILL_RATIO_DENOM         4
171 #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)
172
173 #define JIT_INFO_TABLE_LOW_WATERMARK(n)         ((n) / 2)
174 #define JIT_INFO_TABLE_HIGH_WATERMARK(n)        ((n) * 5 / 6)
175
176 #define JIT_INFO_TOMBSTONE_MARKER       ((MonoMethod*)NULL)
177 #define IS_JIT_INFO_TOMBSTONE(ji)       ((ji)->method == JIT_INFO_TOMBSTONE_MARKER)
178
179 #define JIT_INFO_TABLE_HAZARD_INDEX             0
180 #define JIT_INFO_HAZARD_INDEX                   1
181
182 static int
183 jit_info_table_num_elements (MonoJitInfoTable *table)
184 {
185         int i;
186         int num_elements = 0;
187
188         for (i = 0; i < table->num_chunks; ++i) {
189                 MonoJitInfoTableChunk *chunk = table->chunks [i];
190                 int chunk_num_elements = chunk->num_elements;
191                 int j;
192
193                 for (j = 0; j < chunk_num_elements; ++j) {
194                         if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j]))
195                                 ++num_elements;
196                 }
197         }
198
199         return num_elements;
200 }
201
202 static MonoJitInfoTableChunk*
203 jit_info_table_new_chunk (void)
204 {
205         MonoJitInfoTableChunk *chunk = g_new0 (MonoJitInfoTableChunk, 1);
206         chunk->refcount = 1;
207
208         return chunk;
209 }
210
211 static MonoJitInfoTable *
212 jit_info_table_new (MonoDomain *domain)
213 {
214         MonoJitInfoTable *table = g_malloc0 (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*));
215
216         table->domain = domain;
217         table->num_chunks = 1;
218         table->chunks [0] = jit_info_table_new_chunk ();
219
220         return table;
221 }
222
223 static void
224 jit_info_table_free (MonoJitInfoTable *table)
225 {
226         int i;
227         int num_chunks = table->num_chunks;
228         MonoDomain *domain = table->domain;
229
230         mono_domain_lock (domain);
231
232         table->domain->num_jit_info_tables--;
233         if (table->domain->num_jit_info_tables <= 1) {
234                 GSList *list;
235
236                 for (list = table->domain->jit_info_free_queue; list; list = list->next)
237                         g_free (list->data);
238
239                 g_slist_free (table->domain->jit_info_free_queue);
240                 table->domain->jit_info_free_queue = NULL;
241         }
242
243         /* At this point we assume that there are no other threads
244            still accessing the table, so we don't have to worry about
245            hazardous pointers. */
246
247         for (i = 0; i < num_chunks; ++i) {
248                 MonoJitInfoTableChunk *chunk = table->chunks [i];
249                 int num_elements;
250                 int j;
251
252                 if (--chunk->refcount > 0)
253                         continue;
254
255                 num_elements = chunk->num_elements;
256                 for (j = 0; j < num_elements; ++j) {
257                         MonoJitInfo *ji = chunk->data [j];
258
259                         if (IS_JIT_INFO_TOMBSTONE (ji))
260                                 g_free (ji);
261                 }
262
263                 g_free (chunk);
264         }
265
266         mono_domain_unlock (domain);
267
268         g_free (table);
269 }
270
271 /* The jit_info_table is sorted in ascending order by the end
272  * addresses of the compiled methods.  The reason why we have to do
273  * this is that once we introduce tombstones, it becomes possible for
274  * code ranges to overlap, and if we sort by code start and insert at
275  * the back of the table, we cannot guarantee that we won't overlook
276  * an entry.
277  *
278  * There are actually two possible ways to do the sorting and
279  * inserting which work with our lock-free mechanism:
280  *
281  * 1. Sort by start address and insert at the front.  When looking for
282  * an entry, find the last one with a start address lower than the one
283  * you're looking for, then work your way to the front of the table.
284  *
285  * 2. Sort by end address and insert at the back.  When looking for an
286  * entry, find the first one with an end address higher than the one
287  * you're looking for, then work your way to the end of the table.
288  *
289  * We chose the latter out of convenience.
290  */
291 static int
292 jit_info_table_index (MonoJitInfoTable *table, gint8 *addr)
293 {
294         int left = 0, right = table->num_chunks;
295
296         g_assert (left < right);
297
298         do {
299                 int pos = (left + right) / 2;
300                 MonoJitInfoTableChunk *chunk = table->chunks [pos];
301
302                 if (addr < chunk->last_code_end)
303                         right = pos;
304                 else
305                         left = pos + 1;
306         } while (left < right);
307         g_assert (left == right);
308
309         if (left >= table->num_chunks)
310                 return table->num_chunks - 1;
311         return left;
312 }
313
314 static int
315 jit_info_table_chunk_index (MonoJitInfoTableChunk *chunk, MonoThreadHazardPointers *hp, gint8 *addr)
316 {
317         int left = 0, right = chunk->num_elements;
318
319         while (left < right) {
320                 int pos = (left + right) / 2;
321                 MonoJitInfo *ji = get_hazardous_pointer((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
322                 gint8 *code_end = (gint8*)ji->code_start + ji->code_size;
323
324                 if (addr < code_end)
325                         right = pos;
326                 else
327                         left = pos + 1;
328         }
329         g_assert (left == right);
330
331         return left;
332 }
333
334 MonoJitInfo*
335 mono_jit_info_table_find (MonoDomain *domain, char *addr)
336 {
337         MonoJitInfoTable *table;
338         MonoJitInfo *ji;
339         int chunk_pos, pos;
340         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
341         MonoImage *image;
342
343         ++mono_stats.jit_info_table_lookup_count;
344
345         /* First we have to get the domain's jit_info_table.  This is
346            complicated by the fact that a writer might substitute a
347            new table and free the old one.  What the writer guarantees
348            us is that it looks at the hazard pointers after it has
349            changed the jit_info_table pointer.  So, if we guard the
350            table by a hazard pointer and make sure that the pointer is
351            still there after we've made it hazardous, we don't have to
352            worry about the writer freeing the table. */
353         table = get_hazardous_pointer ((gpointer volatile*)&domain->jit_info_table, hp, JIT_INFO_TABLE_HAZARD_INDEX);
354
355         chunk_pos = jit_info_table_index (table, (gint8*)addr);
356         g_assert (chunk_pos < table->num_chunks);
357
358         pos = jit_info_table_chunk_index (table->chunks [chunk_pos], hp, (gint8*)addr);
359
360         /* We now have a position that's very close to that of the
361            first element whose end address is higher than the one
362            we're looking for.  If we don't have the exact position,
363            then we have a position below that one, so we'll just
364            search upward until we find our element. */
365         do {
366                 MonoJitInfoTableChunk *chunk = table->chunks [chunk_pos];
367
368                 while (pos < chunk->num_elements) {
369                         ji = get_hazardous_pointer ((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
370
371                         ++pos;
372
373                         if (IS_JIT_INFO_TOMBSTONE (ji)) {
374                                 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
375                                 continue;
376                         }
377                         if ((gint8*)addr >= (gint8*)ji->code_start
378                                         && (gint8*)addr < (gint8*)ji->code_start + ji->code_size) {
379                                 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
380                                 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
381                                 return ji;
382                         }
383
384                         /* If we find a non-tombstone element which is already
385                            beyond what we're looking for, we have to end the
386                            search. */
387                         if ((gint8*)addr < (gint8*)ji->code_start)
388                                 goto not_found;
389                 }
390
391                 ++chunk_pos;
392                 pos = 0;
393         } while (chunk_pos < table->num_chunks);
394
395  not_found:
396         if (!hp)
397                 return NULL;
398
399         mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
400         mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
401
402         ji = NULL;
403
404         /* Maybe its an AOT module */
405         image = mono_jit_info_find_aot_module ((guint8*)addr);
406         if (image)
407                 ji = jit_info_find_in_aot_func (domain, image, addr);
408         
409         return ji;
410 }
411
412 static G_GNUC_UNUSED void
413 jit_info_table_check (MonoJitInfoTable *table)
414 {
415         int i;
416
417         for (i = 0; i < table->num_chunks; ++i) {
418                 MonoJitInfoTableChunk *chunk = table->chunks [i];
419                 int j;
420
421                 g_assert (chunk->refcount > 0 /* && chunk->refcount <= 8 */);
422                 if (chunk->refcount > 10)
423                         printf("warning: chunk refcount is %d\n", chunk->refcount);
424                 g_assert (chunk->num_elements <= MONO_JIT_INFO_TABLE_CHUNK_SIZE);
425
426                 for (j = 0; j < chunk->num_elements; ++j) {
427                         MonoJitInfo *this = chunk->data [j];
428                         MonoJitInfo *next;
429
430                         g_assert ((gint8*)this->code_start + this->code_size <= chunk->last_code_end);
431
432                         if (j < chunk->num_elements - 1)
433                                 next = chunk->data [j + 1];
434                         else if (i < table->num_chunks - 1) {
435                                 int k;
436
437                                 for (k = i + 1; k < table->num_chunks; ++k)
438                                         if (table->chunks [k]->num_elements > 0)
439                                                 break;
440
441                                 if (k >= table->num_chunks)
442                                         return;
443
444                                 g_assert (table->chunks [k]->num_elements > 0);
445                                 next = table->chunks [k]->data [0];
446                         } else
447                                 return;
448
449                         g_assert ((gint8*)this->code_start + this->code_size <= (gint8*)next->code_start + next->code_size);
450                 }
451         }
452 }
453
454 static MonoJitInfoTable*
455 jit_info_table_realloc (MonoJitInfoTable *old)
456 {
457         int i;
458         int num_elements = jit_info_table_num_elements (old);
459         int required_size;
460         int num_chunks;
461         int new_chunk, new_element;
462         MonoJitInfoTable *new;
463
464         /* number of needed places for elements needed */
465         required_size = (int)((long)num_elements * JIT_INFO_TABLE_FILL_RATIO_DENOM / JIT_INFO_TABLE_FILL_RATIO_NOM);
466         num_chunks = (required_size + MONO_JIT_INFO_TABLE_CHUNK_SIZE - 1) / MONO_JIT_INFO_TABLE_CHUNK_SIZE;
467         if (num_chunks == 0) {
468                 g_assert (num_elements == 0);
469                 return jit_info_table_new (old->domain);
470         }
471         g_assert (num_chunks > 0);
472
473         new = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*) * num_chunks);
474         new->domain = old->domain;
475         new->num_chunks = num_chunks;
476
477         for (i = 0; i < num_chunks; ++i)
478                 new->chunks [i] = jit_info_table_new_chunk ();
479
480         new_chunk = 0;
481         new_element = 0;
482         for (i = 0; i < old->num_chunks; ++i) {
483                 MonoJitInfoTableChunk *chunk = old->chunks [i];
484                 int chunk_num_elements = chunk->num_elements;
485                 int j;
486
487                 for (j = 0; j < chunk_num_elements; ++j) {
488                         if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j])) {
489                                 g_assert (new_chunk < num_chunks);
490                                 new->chunks [new_chunk]->data [new_element] = chunk->data [j];
491                                 if (++new_element >= JIT_INFO_TABLE_FILLED_NUM_ELEMENTS) {
492                                         new->chunks [new_chunk]->num_elements = new_element;
493                                         ++new_chunk;
494                                         new_element = 0;
495                                 }
496                         }
497                 }
498         }
499
500         if (new_chunk < num_chunks) {
501                 g_assert (new_chunk == num_chunks - 1);
502                 new->chunks [new_chunk]->num_elements = new_element;
503                 g_assert (new->chunks [new_chunk]->num_elements > 0);
504         }
505
506         for (i = 0; i < num_chunks; ++i) {
507                 MonoJitInfoTableChunk *chunk = new->chunks [i];
508                 MonoJitInfo *ji = chunk->data [chunk->num_elements - 1];
509
510                 new->chunks [i]->last_code_end = (gint8*)ji->code_start + ji->code_size;
511         }
512
513         return new;
514 }
515
516 static void
517 jit_info_table_split_chunk (MonoJitInfoTableChunk *chunk, MonoJitInfoTableChunk **new1p, MonoJitInfoTableChunk **new2p)
518 {
519         MonoJitInfoTableChunk *new1 = jit_info_table_new_chunk ();
520         MonoJitInfoTableChunk *new2 = jit_info_table_new_chunk ();
521
522         g_assert (chunk->num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE);
523
524         new1->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE / 2;
525         new2->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE - new1->num_elements;
526
527         memcpy ((void*)new1->data, (void*)chunk->data, sizeof (MonoJitInfo*) * new1->num_elements);
528         memcpy ((void*)new2->data, (void*)(chunk->data + new1->num_elements), sizeof (MonoJitInfo*) * new2->num_elements);
529
530         new1->last_code_end = (gint8*)new1->data [new1->num_elements - 1]->code_start
531                 + new1->data [new1->num_elements - 1]->code_size;
532         new2->last_code_end = (gint8*)new2->data [new2->num_elements - 1]->code_start
533                 + new2->data [new2->num_elements - 1]->code_size;
534
535         *new1p = new1;
536         *new2p = new2;
537 }
538
539 static MonoJitInfoTable*
540 jit_info_table_copy_and_split_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
541 {
542         MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
543                 + sizeof (MonoJitInfoTableChunk*) * (table->num_chunks + 1));
544         int i, j;
545
546         new_table->domain = table->domain;
547         new_table->num_chunks = table->num_chunks + 1;
548
549         j = 0;
550         for (i = 0; i < table->num_chunks; ++i) {
551                 if (table->chunks [i] == chunk) {
552                         jit_info_table_split_chunk (chunk, &new_table->chunks [j], &new_table->chunks [j + 1]);
553                         j += 2;
554                 } else {
555                         new_table->chunks [j] = table->chunks [i];
556                         ++new_table->chunks [j]->refcount;
557                         ++j;
558                 }
559         }
560
561         g_assert (j == new_table->num_chunks);
562
563         return new_table;
564 }
565
566 static MonoJitInfoTableChunk*
567 jit_info_table_purify_chunk (MonoJitInfoTableChunk *old)
568 {
569         MonoJitInfoTableChunk *new = jit_info_table_new_chunk ();
570         int i, j;
571
572         j = 0;
573         for (i = 0; i < old->num_elements; ++i) {
574                 if (!IS_JIT_INFO_TOMBSTONE (old->data [i]))
575                         new->data [j++] = old->data [i];
576         }
577
578         new->num_elements = j;
579         if (new->num_elements > 0)
580                 new->last_code_end = (gint8*)new->data [j - 1]->code_start + new->data [j - 1]->code_size;
581         else
582                 new->last_code_end = old->last_code_end;
583
584         return new;
585 }
586
587 static MonoJitInfoTable*
588 jit_info_table_copy_and_purify_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
589 {
590         MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
591                 + sizeof (MonoJitInfoTableChunk*) * table->num_chunks);
592         int i, j;
593
594         new_table->domain = table->domain;
595         new_table->num_chunks = table->num_chunks;
596
597         j = 0;
598         for (i = 0; i < table->num_chunks; ++i) {
599                 if (table->chunks [i] == chunk)
600                         new_table->chunks [j++] = jit_info_table_purify_chunk (table->chunks [i]);
601                 else {
602                         new_table->chunks [j] = table->chunks [i];
603                         ++new_table->chunks [j]->refcount;
604                         ++j;
605                 }
606         }
607
608         g_assert (j == new_table->num_chunks);
609
610         return new_table;
611 }
612
613 /* As we add an element to the table the case can arise that the chunk
614  * to which we need to add is already full.  In that case we have to
615  * allocate a new table and do something about that chunk.  We have
616  * several strategies:
617  *
618  * If the number of elements in the table is below the low watermark
619  * or above the high watermark, we reallocate the whole table.
620  * Otherwise we only concern ourselves with the overflowing chunk:
621  *
622  * If there are no tombstones in the chunk then we split the chunk in
623  * two, each half full.
624  *
625  * If the chunk does contain tombstones, we just make a new copy of
626  * the chunk without the tombstones, which will have room for at least
627  * the one element we have to add.
628  */
629 static MonoJitInfoTable*
630 jit_info_table_chunk_overflow (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
631 {
632         int num_elements = jit_info_table_num_elements (table);
633         int i;
634
635         if (num_elements < JIT_INFO_TABLE_LOW_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)
636                         || num_elements > JIT_INFO_TABLE_HIGH_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)) {
637                 //printf ("reallocing table\n");
638                 return jit_info_table_realloc (table);
639         }
640
641         /* count the number of non-tombstone elements in the chunk */
642         num_elements = 0;
643         for (i = 0; i < chunk->num_elements; ++i) {
644                 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [i]))
645                         ++num_elements;
646         }
647
648         if (num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
649                 //printf ("splitting chunk\n");
650                 return jit_info_table_copy_and_split_chunk (table, chunk);
651         }
652
653         //printf ("purifying chunk\n");
654         return jit_info_table_copy_and_purify_chunk (table, chunk);
655 }
656
657 /* We add elements to the table by first making space for them by
658  * shifting the elements at the back to the right, one at a time.
659  * This results in duplicate entries during the process, but during
660  * all the time the table is in a sorted state.  Also, when an element
661  * is replaced by another one, the element that replaces it has an end
662  * address that is equal to or lower than that of the replaced
663  * element.  That property is necessary to guarantee that when
664  * searching for an element we end up at a position not higher than
665  * the one we're looking for (i.e. we either find the element directly
666  * or we end up to the left of it).
667  */
668 void
669 mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
670 {
671         MonoJitInfoTable *table;
672         int chunk_pos, pos;
673         MonoJitInfoTableChunk *chunk;
674         int num_elements;
675         int i;
676
677         g_assert (ji->method != NULL);
678
679         mono_domain_lock (domain);
680
681         ++mono_stats.jit_info_table_insert_count;
682
683         table = domain->jit_info_table;
684
685  restart:
686         chunk_pos = jit_info_table_index (table, (gint8*)ji->code_start + ji->code_size);
687         g_assert (chunk_pos < table->num_chunks);
688         chunk = table->chunks [chunk_pos];
689
690         if (chunk->num_elements >= MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
691                 MonoJitInfoTable *new_table = jit_info_table_chunk_overflow (table, chunk);
692
693                 /* Debugging code, should be removed. */
694                 //jit_info_table_check (new_table);
695
696                 domain->jit_info_table = new_table;
697                 mono_memory_barrier ();
698                 domain->num_jit_info_tables++;
699                 mono_thread_hazardous_free_or_queue (table, (MonoHazardousFreeFunc)jit_info_table_free, TRUE, FALSE);
700                 table = new_table;
701
702                 goto restart;
703         }
704
705         /* Debugging code, should be removed. */
706         //jit_info_table_check (table);
707
708         num_elements = chunk->num_elements;
709
710         pos = jit_info_table_chunk_index (chunk, NULL, (gint8*)ji->code_start + ji->code_size);
711
712         /* First we need to size up the chunk by one, by copying the
713            last item, or inserting the first one, if the table is
714            empty. */
715         if (num_elements > 0)
716                 chunk->data [num_elements] = chunk->data [num_elements - 1];
717         else
718                 chunk->data [0] = ji;
719         mono_memory_write_barrier ();
720         chunk->num_elements = ++num_elements;
721
722         /* Shift the elements up one by one. */
723         for (i = num_elements - 2; i >= pos; --i) {
724                 mono_memory_write_barrier ();
725                 chunk->data [i + 1] = chunk->data [i];
726         }
727
728         /* Now we have room and can insert the new item. */
729         mono_memory_write_barrier ();
730         chunk->data [pos] = ji;
731
732         /* Set the high code end address chunk entry. */
733         chunk->last_code_end = (gint8*)chunk->data [chunk->num_elements - 1]->code_start
734                 + chunk->data [chunk->num_elements - 1]->code_size;
735
736         /* Debugging code, should be removed. */
737         //jit_info_table_check (table);
738
739         mono_domain_unlock (domain);
740 }
741
742 static MonoJitInfo*
743 mono_jit_info_make_tombstone (MonoJitInfo *ji)
744 {
745         MonoJitInfo *tombstone = g_new0 (MonoJitInfo, 1);
746
747         tombstone->code_start = ji->code_start;
748         tombstone->code_size = ji->code_size;
749         tombstone->method = JIT_INFO_TOMBSTONE_MARKER;
750
751         return tombstone;
752 }
753
754 /*
755  * LOCKING: domain lock
756  */
757 static void
758 mono_jit_info_free_or_queue (MonoDomain *domain, MonoJitInfo *ji)
759 {
760         if (domain->num_jit_info_tables <= 1) {
761                 /* Can it actually happen that we only have one table
762                    but ji is still hazardous? */
763                 mono_thread_hazardous_free_or_queue (ji, g_free, TRUE, FALSE);
764         } else {
765                 domain->jit_info_free_queue = g_slist_prepend (domain->jit_info_free_queue, ji);
766         }
767 }
768
769 void
770 mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
771 {
772         MonoJitInfoTable *table;
773         MonoJitInfoTableChunk *chunk;
774         gpointer start = ji->code_start;
775         int chunk_pos, pos;
776
777         mono_domain_lock (domain);
778         table = domain->jit_info_table;
779
780         ++mono_stats.jit_info_table_remove_count;
781
782         chunk_pos = jit_info_table_index (table, start);
783         g_assert (chunk_pos < table->num_chunks);
784
785         pos = jit_info_table_chunk_index (table->chunks [chunk_pos], NULL, start);
786
787         do {
788                 chunk = table->chunks [chunk_pos];
789
790                 while (pos < chunk->num_elements) {
791                         if (chunk->data [pos] == ji)
792                                 goto found;
793
794                         g_assert (IS_JIT_INFO_TOMBSTONE (chunk->data [pos]));
795                         g_assert ((guint8*)chunk->data [pos]->code_start + chunk->data [pos]->code_size
796                                 <= (guint8*)ji->code_start + ji->code_size);
797
798                         ++pos;
799                 }
800
801                 ++chunk_pos;
802                 pos = 0;
803         } while (chunk_pos < table->num_chunks);
804
805  found:
806         g_assert (chunk->data [pos] == ji);
807
808         chunk->data [pos] = mono_jit_info_make_tombstone (ji);
809
810         /* Debugging code, should be removed. */
811         //jit_info_table_check (table);
812
813         mono_jit_info_free_or_queue (domain, ji);
814
815         mono_domain_unlock (domain);
816 }
817
818 static MonoAotModuleInfoTable*
819 mono_aot_module_info_table_new (void)
820 {
821         return g_array_new (FALSE, FALSE, sizeof (gpointer));
822 }
823
824 static int
825 aot_info_table_index (MonoAotModuleInfoTable *table, char *addr)
826 {
827         int left = 0, right = table->len;
828
829         while (left < right) {
830                 int pos = (left + right) / 2;
831                 AotModuleInfo *ainfo = g_array_index (table, gpointer, pos);
832                 char *start = ainfo->start;
833                 char *end = ainfo->end;
834
835                 if (addr < start)
836                         right = pos;
837                 else if (addr >= end) 
838                         left = pos + 1;
839                 else
840                         return pos;
841         }
842
843         return left;
844 }
845
846 void
847 mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
848 {
849         AotModuleInfo *ainfo = g_new0 (AotModuleInfo, 1);
850         int pos;
851
852         ainfo->image = image;
853         ainfo->start = start;
854         ainfo->end = end;
855
856         mono_appdomains_lock ();
857
858         if (!aot_modules)
859                 aot_modules = mono_aot_module_info_table_new ();
860
861         pos = aot_info_table_index (aot_modules, start);
862
863         g_array_insert_val (aot_modules, pos, ainfo);
864
865         mono_appdomains_unlock ();
866 }
867
868 static MonoImage*
869 mono_jit_info_find_aot_module (guint8* addr)
870 {
871         guint left = 0, right;
872
873         if (!aot_modules)
874                 return NULL;
875
876         mono_appdomains_lock ();
877
878         right = aot_modules->len;
879         while (left < right) {
880                 guint pos = (left + right) / 2;
881                 AotModuleInfo *ai = g_array_index (aot_modules, gpointer, pos);
882
883                 if (addr < (guint8*)ai->start)
884                         right = pos;
885                 else if (addr >= (guint8*)ai->end)
886                         left = pos + 1;
887                 else {
888                         mono_appdomains_unlock ();
889                         return ai->image;
890                 }
891         }
892
893         mono_appdomains_unlock ();
894
895         return NULL;
896 }
897
898 void
899 mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func)
900 {
901         jit_info_find_in_aot_func = func;
902 }
903
904 gpointer
905 mono_jit_info_get_code_start (MonoJitInfo* ji)
906 {
907         return ji->code_start;
908 }
909
910 int
911 mono_jit_info_get_code_size (MonoJitInfo* ji)
912 {
913         return ji->code_size;
914 }
915
916 MonoMethod*
917 mono_jit_info_get_method (MonoJitInfo* ji)
918 {
919         return ji->method;
920 }
921
922 static gpointer
923 jit_info_key_extract (gpointer value)
924 {
925         MonoJitInfo *info = (MonoJitInfo*)value;
926
927         return info->method;
928 }
929
930 static gpointer*
931 jit_info_next_value (gpointer value)
932 {
933         MonoJitInfo *info = (MonoJitInfo*)value;
934
935         return (gpointer*)&info->next_jit_code_hash;
936 }
937
938 void
939 mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
940 {
941         mono_internal_hash_table_init (jit_code_hash,
942                                        mono_aligned_addr_hash,
943                                        jit_info_key_extract,
944                                        jit_info_next_value);
945 }
946
947 MonoGenericJitInfo*
948 mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
949 {
950         if (ji->has_generic_jit_info)
951                 return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
952         else
953                 return NULL;
954 }
955
956 /*
957  * mono_jit_info_get_generic_sharing_context:
958  * @ji: a jit info
959  *
960  * Returns the jit info's generic sharing context, or NULL if it
961  * doesn't have one.
962  */
963 MonoGenericSharingContext*
964 mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
965 {
966         MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
967
968         if (gi)
969                 return gi->generic_sharing_context;
970         else
971                 return NULL;
972 }
973
974 /*
975  * mono_jit_info_set_generic_sharing_context:
976  * @ji: a jit info
977  * @gsctx: a generic sharing context
978  *
979  * Sets the jit info's generic sharing context.  The jit info must
980  * have memory allocated for the context.
981  */
982 void
983 mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
984 {
985         MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
986
987         g_assert (gi);
988
989         gi->generic_sharing_context = gsctx;
990 }
991
992 MonoTryBlockHoleTableJitInfo*
993 mono_jit_info_get_try_block_hole_table_info (MonoJitInfo *ji)
994 {
995         if (ji->has_try_block_holes) {
996                 char *ptr = (char*)&ji->clauses [ji->num_clauses];
997                 if (ji->has_generic_jit_info)
998                         ptr += sizeof (MonoGenericJitInfo);
999                 return (MonoTryBlockHoleTableJitInfo*)ptr;
1000         } else {
1001                 return NULL;
1002         }
1003 }
1004
1005 MonoArchEHJitInfo*
1006 mono_jit_info_get_arch_eh_info (MonoJitInfo *ji)
1007 {
1008         if (ji->has_arch_eh_info) {
1009                 char *ptr = (char*)&ji->clauses [ji->num_clauses];
1010                 if (ji->has_generic_jit_info)
1011                         ptr += sizeof (MonoGenericJitInfo);
1012                 if (ji->has_try_block_holes)
1013                         ptr += sizeof (MonoTryBlockHoleTableJitInfo);
1014                 return (MonoArchEHJitInfo*)ptr;
1015         } else {
1016                 return NULL;
1017         }
1018 }
1019
1020 MonoMethodCasInfo*
1021 mono_jit_info_get_cas_info (MonoJitInfo *ji)
1022 {
1023         if (ji->has_cas_info) {
1024                 char *ptr = (char*)&ji->clauses [ji->num_clauses];
1025                 if (ji->has_generic_jit_info)
1026                         ptr += sizeof (MonoGenericJitInfo);
1027                 if (ji->has_try_block_holes)
1028                         ptr += sizeof (MonoTryBlockHoleTableJitInfo);
1029                 if (ji->has_arch_eh_info)
1030                         ptr += sizeof (MonoArchEHJitInfo);
1031                 return (MonoMethodCasInfo*)ptr;
1032         } else {
1033                 return NULL;
1034         }
1035 }
1036
1037 void
1038 mono_install_create_domain_hook (MonoCreateDomainFunc func)
1039 {
1040         create_domain_hook = func;
1041 }
1042
1043 void
1044 mono_install_free_domain_hook (MonoFreeDomainFunc func)
1045 {
1046         free_domain_hook = func;
1047 }
1048
1049 /**
1050  * mono_string_equal:
1051  * @s1: First string to compare
1052  * @s2: Second string to compare
1053  *
1054  * Returns FALSE if the strings differ.
1055  */
1056 gboolean
1057 mono_string_equal (MonoString *s1, MonoString *s2)
1058 {
1059         int l1 = mono_string_length (s1);
1060         int l2 = mono_string_length (s2);
1061
1062         if (s1 == s2)
1063                 return TRUE;
1064         if (l1 != l2)
1065                 return FALSE;
1066
1067         return memcmp (mono_string_chars (s1), mono_string_chars (s2), l1 * 2) == 0; 
1068 }
1069
1070 /**
1071  * mono_string_hash:
1072  * @s: the string to hash
1073  *
1074  * Returns the hash for the string.
1075  */
1076 guint
1077 mono_string_hash (MonoString *s)
1078 {
1079         const guint16 *p = mono_string_chars (s);
1080         int i, len = mono_string_length (s);
1081         guint h = 0;
1082
1083         for (i = 0; i < len; i++) {
1084                 h = (h << 5) - h + *p;
1085                 p++;
1086         }
1087
1088         return h;       
1089 }
1090
1091 static gboolean
1092 mono_ptrarray_equal (gpointer *s1, gpointer *s2)
1093 {
1094         int len = GPOINTER_TO_INT (s1 [0]);
1095         if (len != GPOINTER_TO_INT (s2 [0]))
1096                 return FALSE;
1097
1098         return memcmp (s1 + 1, s2 + 1, len * sizeof(gpointer)) == 0; 
1099 }
1100
1101 static guint
1102 mono_ptrarray_hash (gpointer *s)
1103 {
1104         int i;
1105         int len = GPOINTER_TO_INT (s [0]);
1106         guint hash = 0;
1107         
1108         for (i = 1; i < len; i++)
1109                 hash += GPOINTER_TO_UINT (s [i]);
1110
1111         return hash;    
1112 }
1113
1114 /*
1115  * Allocate an id for domain and set domain->domain_id.
1116  * LOCKING: must be called while holding appdomains_mutex.
1117  * We try to assign low numbers to the domain, so it can be used
1118  * as an index in data tables to lookup domain-specific info
1119  * with minimal memory overhead. We also try not to reuse the
1120  * same id too quickly (to help debugging).
1121  */
1122 static int
1123 domain_id_alloc (MonoDomain *domain)
1124 {
1125         int id = -1, i;
1126         if (!appdomains_list) {
1127                 appdomain_list_size = 2;
1128                 appdomains_list = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1129         }
1130         for (i = appdomain_next; i < appdomain_list_size; ++i) {
1131                 if (!appdomains_list [i]) {
1132                         id = i;
1133                         break;
1134                 }
1135         }
1136         if (id == -1) {
1137                 for (i = 0; i < appdomain_next; ++i) {
1138                         if (!appdomains_list [i]) {
1139                                 id = i;
1140                                 break;
1141                         }
1142                 }
1143         }
1144         if (id == -1) {
1145                 MonoDomain **new_list;
1146                 int new_size = appdomain_list_size * 2;
1147                 if (new_size >= (1 << 16))
1148                         g_assert_not_reached ();
1149                 id = appdomain_list_size;
1150                 new_list = mono_gc_alloc_fixed (new_size * sizeof (void*), NULL);
1151                 memcpy (new_list, appdomains_list, appdomain_list_size * sizeof (void*));
1152                 mono_gc_free_fixed (appdomains_list);
1153                 appdomains_list = new_list;
1154                 appdomain_list_size = new_size;
1155         }
1156         domain->domain_id = id;
1157         appdomains_list [id] = domain;
1158         appdomain_next++;
1159         if (appdomain_next > appdomain_list_size)
1160                 appdomain_next = 0;
1161         return id;
1162 }
1163
1164 static gsize domain_gc_bitmap [sizeof(MonoDomain)/4/32 + 1];
1165 static gpointer domain_gc_desc = NULL;
1166 static guint32 domain_shadow_serial = 0L;
1167
1168 MonoDomain *
1169 mono_domain_create (void)
1170 {
1171         MonoDomain *domain;
1172         guint32 shadow_serial;
1173   
1174         mono_appdomains_lock ();
1175         shadow_serial = domain_shadow_serial++;
1176   
1177         if (!domain_gc_desc) {
1178                 unsigned int i, bit = 0;
1179                 for (i = G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_OBJECT); i < G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_GC_TRACKED); i += sizeof (gpointer)) {
1180                         bit = i / sizeof (gpointer);
1181                         domain_gc_bitmap [bit / 32] |= (gsize) 1 << (bit % 32);
1182                 }
1183                 domain_gc_desc = mono_gc_make_descr_from_bitmap ((gsize*)domain_gc_bitmap, bit + 1);
1184         }
1185         mono_appdomains_unlock ();
1186
1187 #ifdef HAVE_BOEHM_GC
1188         /*
1189          * Boehm doesn't like roots inside GC allocated objects, and alloc_fixed returns
1190          * a GC_MALLOC-ed object, contrary to the api docs. This causes random crashes when
1191          * running the corlib test suite.
1192          * To solve this, we pass a NULL descriptor, and don't register roots.
1193          */
1194         domain = mono_gc_alloc_fixed (sizeof (MonoDomain), NULL);
1195 #else
1196         domain = mono_gc_alloc_fixed (sizeof (MonoDomain), domain_gc_desc);
1197         mono_gc_register_root ((char*)&(domain->MONO_DOMAIN_FIRST_GC_TRACKED), G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_LAST_GC_TRACKED) - G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_GC_TRACKED), NULL);
1198 #endif
1199         domain->shadow_serial = shadow_serial;
1200         domain->domain = NULL;
1201         domain->setup = NULL;
1202         domain->friendly_name = NULL;
1203         domain->search_path = NULL;
1204
1205         mono_profiler_appdomain_event (domain, MONO_PROFILE_START_LOAD);
1206
1207         domain->mp = mono_mempool_new ();
1208         domain->code_mp = mono_code_manager_new ();
1209         domain->env = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1210         domain->domain_assemblies = NULL;
1211         domain->assembly_bindings = NULL;
1212         domain->assembly_bindings_parsed = FALSE;
1213         domain->class_vtable_array = g_ptr_array_new ();
1214         domain->proxy_vtable_hash = g_hash_table_new ((GHashFunc)mono_ptrarray_hash, (GCompareFunc)mono_ptrarray_equal);
1215         domain->static_data_array = NULL;
1216         mono_jit_code_hash_init (&domain->jit_code_hash);
1217         domain->ldstr_table = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
1218         domain->num_jit_info_tables = 1;
1219         domain->jit_info_table = jit_info_table_new (domain);
1220         domain->jit_info_free_queue = NULL;
1221         domain->finalizable_objects_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1222         domain->ftnptrs_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1223
1224         InitializeCriticalSection (&domain->lock);
1225         InitializeCriticalSection (&domain->assemblies_lock);
1226         InitializeCriticalSection (&domain->jit_code_hash_lock);
1227         InitializeCriticalSection (&domain->finalizable_objects_hash_lock);
1228
1229         domain->method_rgctx_hash = NULL;
1230
1231         mono_appdomains_lock ();
1232         domain_id_alloc (domain);
1233         mono_appdomains_unlock ();
1234
1235 #ifndef DISABLE_PERFCOUNTERS
1236         mono_perfcounters->loader_appdomains++;
1237         mono_perfcounters->loader_total_appdomains++;
1238 #endif
1239
1240         mono_debug_domain_create (domain);
1241
1242         if (create_domain_hook)
1243                 create_domain_hook (domain);
1244
1245         mono_profiler_appdomain_loaded (domain, MONO_PROFILE_OK);
1246         
1247         return domain;
1248 }
1249
1250 /**
1251  * mono_init_internal:
1252  * 
1253  * Creates the initial application domain and initializes the mono_defaults
1254  * structure.
1255  * This function is guaranteed to not run any IL code.
1256  * If exe_filename is not NULL, the method will determine the required runtime
1257  * from the exe configuration file or the version PE field.
1258  * If runtime_version is not NULL, that runtime version will be used.
1259  * Either exe_filename or runtime_version must be provided.
1260  *
1261  * Returns: the initial domain.
1262  */
1263 static MonoDomain *
1264 mono_init_internal (const char *filename, const char *exe_filename, const char *runtime_version)
1265 {
1266         static MonoDomain *domain = NULL;
1267         MonoAssembly *ass = NULL;
1268         MonoImageOpenStatus status = MONO_IMAGE_OK;
1269         const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
1270         int n;
1271
1272         if (domain)
1273                 g_assert_not_reached ();
1274
1275 #ifdef HOST_WIN32
1276         /* Avoid system error message boxes. */
1277         SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1278 #endif
1279
1280 #ifndef HOST_WIN32
1281         wapi_init ();
1282 #endif
1283
1284 #ifndef DISABLE_PERFCOUNTERS
1285         mono_perfcounters_init ();
1286 #endif
1287
1288         mono_counters_register ("Max native code in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_size);
1289         mono_counters_register ("Max code space allocated in a domain", MONO_COUNTER_INT|MONO_COUNTER_JIT, &max_domain_code_alloc);
1290         mono_counters_register ("Total code space allocated", MONO_COUNTER_INT|MONO_COUNTER_JIT, &total_domain_code_alloc);
1291
1292         mono_gc_base_init ();
1293
1294         MONO_FAST_TLS_INIT (tls_appdomain);
1295         mono_native_tls_alloc (&appdomain_thread_id, NULL);
1296
1297         InitializeCriticalSection (&appdomains_mutex);
1298
1299         mono_metadata_init ();
1300         mono_images_init ();
1301         mono_assemblies_init ();
1302         mono_classes_init ();
1303         mono_loader_init ();
1304         mono_reflection_init ();
1305         mono_runtime_init_tls ();
1306
1307         /* FIXME: When should we release this memory? */
1308         MONO_GC_REGISTER_ROOT_FIXED (appdomains_list);
1309
1310         domain = mono_domain_create ();
1311         mono_root_domain = domain;
1312
1313         SET_APPDOMAIN (domain);
1314         
1315         /* Get a list of runtimes supported by the exe */
1316         if (exe_filename != NULL) {
1317                 /*
1318                  * This function will load the exe file as a MonoImage. We need to close it, but
1319                  * that would mean it would be reloaded later. So instead, we save it to
1320                  * exe_image, and close it during shutdown.
1321                  */
1322                 get_runtimes_from_exe (exe_filename, &exe_image, runtimes);
1323 #ifdef HOST_WIN32
1324                 if (!exe_image) {
1325                         exe_image = mono_assembly_open_from_bundle (exe_filename, NULL, FALSE);
1326                         if (!exe_image)
1327                                 exe_image = mono_image_open (exe_filename, NULL);
1328                 }
1329                 mono_fixup_exe_image (exe_image);
1330 #endif
1331         } else if (runtime_version != NULL) {
1332                 runtimes [0] = get_runtime_by_version (runtime_version);
1333                 runtimes [1] = NULL;
1334         }
1335
1336         if (runtimes [0] == NULL) {
1337                 const MonoRuntimeInfo *default_runtime = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
1338                 runtimes [0] = default_runtime;
1339                 runtimes [1] = NULL;
1340                 g_print ("WARNING: The runtime version supported by this application is unavailable.\n");
1341                 g_print ("Using default runtime: %s\n", default_runtime->runtime_version); 
1342         }
1343
1344         /* The selected runtime will be the first one for which there is a mscrolib.dll */
1345         for (n = 0; runtimes [n] != NULL && ass == NULL; n++) {
1346                 current_runtime = runtimes [n];
1347                 ass = mono_assembly_load_corlib (current_runtime, &status);
1348                 if (status != MONO_IMAGE_OK && status != MONO_IMAGE_ERROR_ERRNO)
1349                         break;
1350
1351         }
1352         
1353         if ((status != MONO_IMAGE_OK) || (ass == NULL)) {
1354                 switch (status){
1355                 case MONO_IMAGE_ERROR_ERRNO: {
1356                         char *corlib_file = g_build_filename (mono_assembly_getrootdir (), "mono", current_runtime->framework_version, "mscorlib.dll", NULL);
1357                         g_print ("The assembly mscorlib.dll was not found or could not be loaded.\n");
1358                         g_print ("It should have been installed in the `%s' directory.\n", corlib_file);
1359                         g_free (corlib_file);
1360                         break;
1361                 }
1362                 case MONO_IMAGE_IMAGE_INVALID:
1363                         g_print ("The file %s/mscorlib.dll is an invalid CIL image\n",
1364                                  mono_assembly_getrootdir ());
1365                         break;
1366                 case MONO_IMAGE_MISSING_ASSEMBLYREF:
1367                         g_print ("Missing assembly reference in %s/mscorlib.dll\n",
1368                                  mono_assembly_getrootdir ());
1369                         break;
1370                 case MONO_IMAGE_OK:
1371                         /* to suppress compiler warning */
1372                         break;
1373                 }
1374                 
1375                 exit (1);
1376         }
1377         mono_defaults.corlib = mono_assembly_get_image (ass);
1378
1379         mono_defaults.object_class = mono_class_from_name (
1380                 mono_defaults.corlib, "System", "Object");
1381         g_assert (mono_defaults.object_class != 0);
1382
1383         mono_defaults.void_class = mono_class_from_name (
1384                 mono_defaults.corlib, "System", "Void");
1385         g_assert (mono_defaults.void_class != 0);
1386
1387         mono_defaults.boolean_class = mono_class_from_name (
1388                 mono_defaults.corlib, "System", "Boolean");
1389         g_assert (mono_defaults.boolean_class != 0);
1390
1391         mono_defaults.byte_class = mono_class_from_name (
1392                 mono_defaults.corlib, "System", "Byte");
1393         g_assert (mono_defaults.byte_class != 0);
1394
1395         mono_defaults.sbyte_class = mono_class_from_name (
1396                 mono_defaults.corlib, "System", "SByte");
1397         g_assert (mono_defaults.sbyte_class != 0);
1398
1399         mono_defaults.int16_class = mono_class_from_name (
1400                 mono_defaults.corlib, "System", "Int16");
1401         g_assert (mono_defaults.int16_class != 0);
1402
1403         mono_defaults.uint16_class = mono_class_from_name (
1404                 mono_defaults.corlib, "System", "UInt16");
1405         g_assert (mono_defaults.uint16_class != 0);
1406
1407         mono_defaults.int32_class = mono_class_from_name (
1408                 mono_defaults.corlib, "System", "Int32");
1409         g_assert (mono_defaults.int32_class != 0);
1410
1411         mono_defaults.uint32_class = mono_class_from_name (
1412                 mono_defaults.corlib, "System", "UInt32");
1413         g_assert (mono_defaults.uint32_class != 0);
1414
1415         mono_defaults.uint_class = mono_class_from_name (
1416                 mono_defaults.corlib, "System", "UIntPtr");
1417         g_assert (mono_defaults.uint_class != 0);
1418
1419         mono_defaults.int_class = mono_class_from_name (
1420                 mono_defaults.corlib, "System", "IntPtr");
1421         g_assert (mono_defaults.int_class != 0);
1422
1423         mono_defaults.int64_class = mono_class_from_name (
1424                 mono_defaults.corlib, "System", "Int64");
1425         g_assert (mono_defaults.int64_class != 0);
1426
1427         mono_defaults.uint64_class = mono_class_from_name (
1428                 mono_defaults.corlib, "System", "UInt64");
1429         g_assert (mono_defaults.uint64_class != 0);
1430
1431         mono_defaults.single_class = mono_class_from_name (
1432                 mono_defaults.corlib, "System", "Single");
1433         g_assert (mono_defaults.single_class != 0);
1434
1435         mono_defaults.double_class = mono_class_from_name (
1436                 mono_defaults.corlib, "System", "Double");
1437         g_assert (mono_defaults.double_class != 0);
1438
1439         mono_defaults.char_class = mono_class_from_name (
1440                 mono_defaults.corlib, "System", "Char");
1441         g_assert (mono_defaults.char_class != 0);
1442
1443         mono_defaults.string_class = mono_class_from_name (
1444                 mono_defaults.corlib, "System", "String");
1445         g_assert (mono_defaults.string_class != 0);
1446
1447         mono_defaults.enum_class = mono_class_from_name (
1448                 mono_defaults.corlib, "System", "Enum");
1449         g_assert (mono_defaults.enum_class != 0);
1450
1451         mono_defaults.array_class = mono_class_from_name (
1452                 mono_defaults.corlib, "System", "Array");
1453         g_assert (mono_defaults.array_class != 0);
1454
1455         mono_defaults.delegate_class = mono_class_from_name (
1456                 mono_defaults.corlib, "System", "Delegate");
1457         g_assert (mono_defaults.delegate_class != 0 );
1458
1459         mono_defaults.multicastdelegate_class = mono_class_from_name (
1460                 mono_defaults.corlib, "System", "MulticastDelegate");
1461         g_assert (mono_defaults.multicastdelegate_class != 0 );
1462
1463         mono_defaults.asyncresult_class = mono_class_from_name (
1464                 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", 
1465                 "AsyncResult");
1466         g_assert (mono_defaults.asyncresult_class != 0 );
1467
1468         mono_defaults.manualresetevent_class = mono_class_from_name (
1469                 mono_defaults.corlib, "System.Threading", "ManualResetEvent");
1470         g_assert (mono_defaults.manualresetevent_class != 0 );
1471
1472         mono_defaults.typehandle_class = mono_class_from_name (
1473                 mono_defaults.corlib, "System", "RuntimeTypeHandle");
1474         g_assert (mono_defaults.typehandle_class != 0);
1475
1476         mono_defaults.methodhandle_class = mono_class_from_name (
1477                 mono_defaults.corlib, "System", "RuntimeMethodHandle");
1478         g_assert (mono_defaults.methodhandle_class != 0);
1479
1480         mono_defaults.fieldhandle_class = mono_class_from_name (
1481                 mono_defaults.corlib, "System", "RuntimeFieldHandle");
1482         g_assert (mono_defaults.fieldhandle_class != 0);
1483
1484         mono_defaults.systemtype_class = mono_class_from_name (
1485                 mono_defaults.corlib, "System", "Type");
1486         g_assert (mono_defaults.systemtype_class != 0);
1487
1488         mono_defaults.monotype_class = mono_class_from_name (
1489                 mono_defaults.corlib, "System", "MonoType");
1490         g_assert (mono_defaults.monotype_class != 0);
1491
1492         mono_defaults.exception_class = mono_class_from_name (
1493                 mono_defaults.corlib, "System", "Exception");
1494         g_assert (mono_defaults.exception_class != 0);
1495
1496         mono_defaults.threadabortexception_class = mono_class_from_name (
1497                 mono_defaults.corlib, "System.Threading", "ThreadAbortException");
1498         g_assert (mono_defaults.threadabortexception_class != 0);
1499
1500         mono_defaults.thread_class = mono_class_from_name (
1501                 mono_defaults.corlib, "System.Threading", "Thread");
1502         g_assert (mono_defaults.thread_class != 0);
1503
1504         mono_defaults.internal_thread_class = mono_class_from_name (
1505                 mono_defaults.corlib, "System.Threading", "InternalThread");
1506         if (!mono_defaults.internal_thread_class) {
1507                 /* This can happen with an old mscorlib */
1508                 fprintf (stderr, "Corlib too old for this runtime.\n");
1509                 fprintf (stderr, "Loaded from: %s\n",
1510                                  mono_defaults.corlib? mono_image_get_filename (mono_defaults.corlib): "unknown");
1511                 exit (1);
1512         }
1513
1514         mono_defaults.appdomain_class = mono_class_from_name (
1515                 mono_defaults.corlib, "System", "AppDomain");
1516         g_assert (mono_defaults.appdomain_class != 0);
1517
1518 #ifndef DISABLE_REMOTING
1519         mono_defaults.transparent_proxy_class = mono_class_from_name (
1520                 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "TransparentProxy");
1521         g_assert (mono_defaults.transparent_proxy_class != 0);
1522
1523         mono_defaults.real_proxy_class = mono_class_from_name (
1524                 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "RealProxy");
1525         g_assert (mono_defaults.real_proxy_class != 0);
1526
1527         mono_defaults.marshalbyrefobject_class =  mono_class_from_name (
1528                 mono_defaults.corlib, "System", "MarshalByRefObject");
1529         g_assert (mono_defaults.marshalbyrefobject_class != 0);
1530
1531         mono_defaults.iremotingtypeinfo_class = mono_class_from_name (
1532                 mono_defaults.corlib, "System.Runtime.Remoting", "IRemotingTypeInfo");
1533         g_assert (mono_defaults.iremotingtypeinfo_class != 0);
1534 #endif
1535
1536         mono_defaults.mono_method_message_class = mono_class_from_name (
1537                 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", "MonoMethodMessage");
1538         g_assert (mono_defaults.mono_method_message_class != 0);
1539
1540         mono_defaults.field_info_class = mono_class_from_name (
1541                 mono_defaults.corlib, "System.Reflection", "FieldInfo");
1542         g_assert (mono_defaults.field_info_class != 0);
1543
1544         mono_defaults.method_info_class = mono_class_from_name (
1545                 mono_defaults.corlib, "System.Reflection", "MethodInfo");
1546         g_assert (mono_defaults.method_info_class != 0);
1547
1548         mono_defaults.stringbuilder_class = mono_class_from_name (
1549                 mono_defaults.corlib, "System.Text", "StringBuilder");
1550         g_assert (mono_defaults.stringbuilder_class != 0);
1551
1552         mono_defaults.math_class = mono_class_from_name (
1553                 mono_defaults.corlib, "System", "Math");
1554         g_assert (mono_defaults.math_class != 0);
1555
1556         mono_defaults.stack_frame_class = mono_class_from_name (
1557                 mono_defaults.corlib, "System.Diagnostics", "StackFrame");
1558         g_assert (mono_defaults.stack_frame_class != 0);
1559
1560         mono_defaults.stack_trace_class = mono_class_from_name (
1561                 mono_defaults.corlib, "System.Diagnostics", "StackTrace");
1562         g_assert (mono_defaults.stack_trace_class != 0);
1563
1564         mono_defaults.marshal_class = mono_class_from_name (
1565                 mono_defaults.corlib, "System.Runtime.InteropServices", "Marshal");
1566         g_assert (mono_defaults.marshal_class != 0);
1567
1568         mono_defaults.typed_reference_class =  mono_class_from_name (
1569                 mono_defaults.corlib, "System", "TypedReference");
1570         g_assert (mono_defaults.typed_reference_class != 0);
1571
1572         mono_defaults.argumenthandle_class =  mono_class_from_name (
1573                 mono_defaults.corlib, "System", "RuntimeArgumentHandle");
1574         g_assert (mono_defaults.argumenthandle_class != 0);
1575
1576         mono_defaults.monitor_class =  mono_class_from_name (
1577                 mono_defaults.corlib, "System.Threading", "Monitor");
1578         g_assert (mono_defaults.monitor_class != 0);
1579
1580         mono_defaults.runtimesecurityframe_class = mono_class_from_name (
1581                 mono_defaults.corlib, "System.Security", "RuntimeSecurityFrame");
1582
1583         mono_defaults.executioncontext_class = mono_class_from_name (
1584                 mono_defaults.corlib, "System.Threading", "ExecutionContext");
1585
1586         mono_defaults.internals_visible_class = mono_class_from_name (
1587                 mono_defaults.corlib, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute");
1588
1589         mono_defaults.critical_finalizer_object = mono_class_from_name (
1590                 mono_defaults.corlib, "System.Runtime.ConstrainedExecution", "CriticalFinalizerObject");
1591
1592         /*
1593          * mscorlib needs a little help, only now it can load its friends list (after we have
1594          * loaded the InternalsVisibleToAttribute), load it now
1595          */
1596         mono_assembly_load_friends (ass);
1597         
1598         mono_defaults.safehandle_class = mono_class_from_name (
1599                 mono_defaults.corlib, "System.Runtime.InteropServices", "SafeHandle");
1600
1601         mono_defaults.handleref_class = mono_class_from_name (
1602                 mono_defaults.corlib, "System.Runtime.InteropServices", "HandleRef");
1603
1604         mono_defaults.attribute_class = mono_class_from_name (
1605                 mono_defaults.corlib, "System", "Attribute");
1606
1607         mono_defaults.customattribute_data_class = mono_class_from_name (
1608                 mono_defaults.corlib, "System.Reflection", "CustomAttributeData");
1609
1610         /* these are initialized lazily when COM features are used */
1611
1612         mono_class_init (mono_defaults.array_class);
1613         mono_defaults.generic_nullable_class = mono_class_from_name (
1614                 mono_defaults.corlib, "System", "Nullable`1");
1615         mono_defaults.generic_ilist_class = mono_class_from_name (
1616                 mono_defaults.corlib, "System.Collections.Generic", "IList`1");
1617         mono_defaults.generic_ireadonlylist_class = mono_class_from_name (
1618                 mono_defaults.corlib, "System.Collections.Generic", "IReadOnlyList`1");
1619
1620         domain->friendly_name = g_path_get_basename (filename);
1621
1622         _mono_debug_init_corlib (domain);
1623
1624         return domain;
1625 }
1626
1627 /**
1628  * mono_init:
1629  * 
1630  * Creates the initial application domain and initializes the mono_defaults
1631  * structure.
1632  * This function is guaranteed to not run any IL code.
1633  * The runtime is initialized using the default runtime version.
1634  *
1635  * Returns: the initial domain.
1636  */
1637 MonoDomain *
1638 mono_init (const char *domain_name)
1639 {
1640         return mono_init_internal (domain_name, NULL, DEFAULT_RUNTIME_VERSION);
1641 }
1642
1643 /**
1644  * mono_init_from_assembly:
1645  * @domain_name: name to give to the initial domain
1646  * @filename: filename to load on startup
1647  *
1648  * Used by the runtime, users should use mono_jit_init instead.
1649  *
1650  * Creates the initial application domain and initializes the mono_defaults
1651  * structure.
1652  * This function is guaranteed to not run any IL code.
1653  * The runtime is initialized using the runtime version required by the
1654  * provided executable. The version is determined by looking at the exe 
1655  * configuration file and the version PE field)
1656  *
1657  * Returns: the initial domain.
1658  */
1659 MonoDomain *
1660 mono_init_from_assembly (const char *domain_name, const char *filename)
1661 {
1662         return mono_init_internal (domain_name, filename, NULL);
1663 }
1664
1665 /**
1666  * mono_init_version:
1667  * 
1668  * Used by the runtime, users should use mono_jit_init instead.
1669  * 
1670  * Creates the initial application domain and initializes the mono_defaults
1671  * structure.
1672  *
1673  * This function is guaranteed to not run any IL code.
1674  * The runtime is initialized using the provided rutime version.
1675  *
1676  * Returns: the initial domain.
1677  */
1678 MonoDomain *
1679 mono_init_version (const char *domain_name, const char *version)
1680 {
1681         return mono_init_internal (domain_name, NULL, version);
1682 }
1683
1684 /**
1685  * mono_cleanup:
1686  *
1687  * Cleans up all metadata modules. 
1688  */
1689 void
1690 mono_cleanup (void)
1691 {
1692         mono_close_exe_image ();
1693
1694         mono_defaults.corlib = NULL;
1695
1696         mono_config_cleanup ();
1697         mono_loader_cleanup ();
1698         mono_classes_cleanup ();
1699         mono_assemblies_cleanup ();
1700         mono_images_cleanup ();
1701         mono_debug_cleanup ();
1702         mono_metadata_cleanup ();
1703
1704         mono_native_tls_free (appdomain_thread_id);
1705         DeleteCriticalSection (&appdomains_mutex);
1706
1707 #ifndef HOST_WIN32
1708         wapi_cleanup ();
1709 #endif
1710 }
1711
1712 void
1713 mono_close_exe_image (void)
1714 {
1715         if (exe_image)
1716                 mono_image_close (exe_image);
1717 }
1718
1719 /**
1720  * mono_get_root_domain:
1721  *
1722  * The root AppDomain is the initial domain created by the runtime when it is
1723  * initialized.  Programs execute on this AppDomain, but can create new ones
1724  * later.   Currently there is no unmanaged API to create new AppDomains, this
1725  * must be done from managed code.
1726  *
1727  * Returns: the root appdomain, to obtain the current domain, use mono_domain_get ()
1728  */
1729 MonoDomain*
1730 mono_get_root_domain (void)
1731 {
1732         return mono_root_domain;
1733 }
1734
1735 /**
1736  * mono_domain_get:
1737  *
1738  * Returns: the current domain, to obtain the root domain use
1739  * mono_get_root_domain().
1740  */
1741 MonoDomain *
1742 mono_domain_get ()
1743 {
1744         return GET_APPDOMAIN ();
1745 }
1746
1747 void
1748 mono_domain_unset (void)
1749 {
1750         SET_APPDOMAIN (NULL);
1751 }
1752
1753 void
1754 mono_domain_set_internal_with_options (MonoDomain *domain, gboolean migrate_exception)
1755 {
1756         MonoInternalThread *thread;
1757
1758         if (mono_domain_get () == domain)
1759                 return;
1760
1761         SET_APPDOMAIN (domain);
1762         SET_APPCONTEXT (domain->default_context);
1763
1764         if (migrate_exception) {
1765                 thread = mono_thread_internal_current ();
1766                 if (!thread->abort_exc)
1767                         return;
1768
1769                 g_assert (thread->abort_exc->object.vtable->domain != domain);
1770                 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
1771                 g_assert (thread->abort_exc->object.vtable->domain == domain);
1772         }
1773 }
1774
1775 /**
1776  * mono_domain_set_internal:
1777  * @domain: the new domain
1778  *
1779  * Sets the current domain to @domain.
1780  */
1781 void
1782 mono_domain_set_internal (MonoDomain *domain)
1783 {
1784         mono_domain_set_internal_with_options (domain, TRUE);
1785 }
1786
1787 void
1788 mono_domain_foreach (MonoDomainFunc func, gpointer user_data)
1789 {
1790         int i, size;
1791         MonoDomain **copy;
1792
1793         /*
1794          * Create a copy of the data to avoid calling the user callback
1795          * inside the lock because that could lead to deadlocks.
1796          * We can do this because this function is not perf. critical.
1797          */
1798         mono_appdomains_lock ();
1799         size = appdomain_list_size;
1800         copy = mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), NULL);
1801         memcpy (copy, appdomains_list, appdomain_list_size * sizeof (void*));
1802         mono_appdomains_unlock ();
1803
1804         for (i = 0; i < size; ++i) {
1805                 if (copy [i])
1806                         func (copy [i], user_data);
1807         }
1808
1809         mono_gc_free_fixed (copy);
1810 }
1811
1812 /**
1813  * mono_domain_assembly_open:
1814  * @domain: the application domain
1815  * @name: file name of the assembly
1816  *
1817  * fixme: maybe we should integrate this with mono_assembly_open ??
1818  */
1819 MonoAssembly *
1820 mono_domain_assembly_open (MonoDomain *domain, const char *name)
1821 {
1822         MonoDomain *current;
1823         MonoAssembly *ass;
1824         GSList *tmp;
1825
1826         mono_domain_assemblies_lock (domain);
1827         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1828                 ass = tmp->data;
1829                 if (strcmp (name, ass->aname.name) == 0) {
1830                         mono_domain_assemblies_unlock (domain);
1831                         return ass;
1832                 }
1833         }
1834         mono_domain_assemblies_unlock (domain);
1835
1836         if (domain != mono_domain_get ()) {
1837                 current = mono_domain_get ();
1838
1839                 mono_domain_set (domain, FALSE);
1840                 ass = mono_assembly_open (name, NULL);
1841                 mono_domain_set (current, FALSE);
1842         } else {
1843                 ass = mono_assembly_open (name, NULL);
1844         }
1845
1846         return ass;
1847 }
1848
1849 static void
1850 unregister_vtable_reflection_type (MonoVTable *vtable)
1851 {
1852         MonoObject *type = vtable->type;
1853
1854         if (type->vtable->klass != mono_defaults.monotype_class)
1855                 MONO_GC_UNREGISTER_ROOT_IF_MOVING (vtable->type);
1856 }
1857
1858 void
1859 mono_domain_free (MonoDomain *domain, gboolean force)
1860 {
1861         int code_size, code_alloc;
1862         GSList *tmp;
1863         if ((domain == mono_root_domain) && !force) {
1864                 g_warning ("cant unload root domain");
1865                 return;
1866         }
1867
1868         if (mono_dont_free_domains)
1869                 return;
1870
1871         mono_profiler_appdomain_event (domain, MONO_PROFILE_START_UNLOAD);
1872
1873         mono_debug_domain_unload (domain);
1874
1875         mono_appdomains_lock ();
1876         appdomains_list [domain->domain_id] = NULL;
1877         mono_appdomains_unlock ();
1878
1879         /* must do this early as it accesses fields and types */
1880         if (domain->special_static_fields) {
1881                 mono_alloc_special_static_data_free (domain->special_static_fields);
1882                 g_hash_table_destroy (domain->special_static_fields);
1883                 domain->special_static_fields = NULL;
1884         }
1885
1886         /*
1887          * We must destroy all these hash tables here because they
1888          * contain references to managed objects belonging to the
1889          * domain.  Once we let the GC clear the domain there must be
1890          * no more such references, or we'll crash if a collection
1891          * occurs.
1892          */
1893         mono_g_hash_table_destroy (domain->ldstr_table);
1894         domain->ldstr_table = NULL;
1895
1896         mono_g_hash_table_destroy (domain->env);
1897         domain->env = NULL;
1898
1899         if (domain->tlsrec_list) {
1900                 mono_thread_destroy_domain_tls (domain);
1901                 domain->tlsrec_list = NULL;
1902         }
1903
1904         mono_reflection_cleanup_domain (domain);
1905
1906         if (domain->type_hash) {
1907                 mono_g_hash_table_destroy (domain->type_hash);
1908                 domain->type_hash = NULL;
1909         }
1910         if (domain->type_init_exception_hash) {
1911                 mono_g_hash_table_destroy (domain->type_init_exception_hash);
1912                 domain->type_init_exception_hash = NULL;
1913         }
1914
1915         if (domain->class_vtable_array) {
1916                 int i;
1917                 for (i = 0; i < domain->class_vtable_array->len; ++i)
1918                         unregister_vtable_reflection_type (g_ptr_array_index (domain->class_vtable_array, i));
1919         }
1920
1921         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1922                 MonoAssembly *ass = tmp->data;
1923                 mono_assembly_release_gc_roots (ass);
1924         }
1925
1926         /* This needs to be done before closing assemblies */
1927         mono_gc_clear_domain (domain);
1928
1929         /* Close dynamic assemblies first, since they have no ref count */
1930         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1931                 MonoAssembly *ass = tmp->data;
1932                 if (!ass->image || !ass->image->dynamic)
1933                         continue;
1934                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading domain %s[%p], assembly %s[%p], ref_count=%d", domain->friendly_name, domain, ass->aname.name, ass, ass->ref_count);
1935                 if (!mono_assembly_close_except_image_pools (ass))
1936                         tmp->data = NULL;
1937         }
1938
1939         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1940                 MonoAssembly *ass = tmp->data;
1941                 if (!ass)
1942                         continue;
1943                 if (!ass->image || ass->image->dynamic)
1944                         continue;
1945                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading domain %s[%p], assembly %s[%p], ref_count=%d", domain->friendly_name, domain, ass->aname.name, ass, ass->ref_count);
1946                 if (!mono_assembly_close_except_image_pools (ass))
1947                         tmp->data = NULL;
1948         }
1949
1950         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1951                 MonoAssembly *ass = tmp->data;
1952                 if (ass)
1953                         mono_assembly_close_finish (ass);
1954         }
1955         g_slist_free (domain->domain_assemblies);
1956         domain->domain_assemblies = NULL;
1957
1958         /* 
1959          * Send this after the assemblies have been unloaded and the domain is still in a 
1960          * usable state.
1961          */
1962         mono_profiler_appdomain_event (domain, MONO_PROFILE_END_UNLOAD);
1963
1964         if (free_domain_hook)
1965                 free_domain_hook (domain);
1966
1967         /* FIXME: free delegate_hash_table when it's used */
1968         if (domain->search_path) {
1969                 g_strfreev (domain->search_path);
1970                 domain->search_path = NULL;
1971         }
1972         domain->create_proxy_for_type_method = NULL;
1973         domain->private_invoke_method = NULL;
1974         domain->default_context = NULL;
1975         domain->out_of_memory_ex = NULL;
1976         domain->null_reference_ex = NULL;
1977         domain->stack_overflow_ex = NULL;
1978         domain->ephemeron_tombstone = NULL;
1979         domain->entry_assembly = NULL;
1980
1981         g_free (domain->friendly_name);
1982         domain->friendly_name = NULL;
1983         g_ptr_array_free (domain->class_vtable_array, TRUE);
1984         domain->class_vtable_array = NULL;
1985         g_hash_table_destroy (domain->proxy_vtable_hash);
1986         domain->proxy_vtable_hash = NULL;
1987         if (domain->static_data_array) {
1988                 mono_gc_free_fixed (domain->static_data_array);
1989                 domain->static_data_array = NULL;
1990         }
1991         mono_internal_hash_table_destroy (&domain->jit_code_hash);
1992
1993         /*
1994          * There might still be jit info tables of this domain which
1995          * are not freed.  Since the domain cannot be in use anymore,
1996          * this will free them.
1997          */
1998         mono_thread_hazardous_try_free_all ();
1999         g_assert (domain->num_jit_info_tables == 1);
2000         jit_info_table_free (domain->jit_info_table);
2001         domain->jit_info_table = NULL;
2002         g_assert (!domain->jit_info_free_queue);
2003
2004         /* collect statistics */
2005         code_alloc = mono_code_manager_size (domain->code_mp, &code_size);
2006         total_domain_code_alloc += code_alloc;
2007         max_domain_code_alloc = MAX (max_domain_code_alloc, code_alloc);
2008         max_domain_code_size = MAX (max_domain_code_size, code_size);
2009
2010 #ifdef DEBUG_DOMAIN_UNLOAD
2011         mono_mempool_invalidate (domain->mp);
2012         mono_code_manager_invalidate (domain->code_mp);
2013 #else
2014 #ifndef DISABLE_PERFCOUNTERS
2015         mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (domain->mp);
2016 #endif
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  
2022
2023         g_hash_table_destroy (domain->finalizable_objects_hash);
2024         domain->finalizable_objects_hash = NULL;
2025         if (domain->method_rgctx_hash) {
2026                 g_hash_table_destroy (domain->method_rgctx_hash);
2027                 domain->method_rgctx_hash = NULL;
2028         }
2029         if (domain->generic_virtual_cases) {
2030                 g_hash_table_destroy (domain->generic_virtual_cases);
2031                 domain->generic_virtual_cases = NULL;
2032         }
2033         if (domain->generic_virtual_thunks) {
2034                 g_hash_table_destroy (domain->generic_virtual_thunks);
2035                 domain->generic_virtual_thunks = NULL;
2036         }
2037         if (domain->ftnptrs_hash) {
2038                 g_hash_table_destroy (domain->ftnptrs_hash);
2039                 domain->ftnptrs_hash = NULL;
2040         }
2041
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;
2047
2048         mono_gc_deregister_root ((char*)&(domain->MONO_DOMAIN_FIRST_GC_TRACKED));
2049
2050         /* FIXME: anything else required ? */
2051
2052         mono_gc_free_fixed (domain);
2053
2054 #ifndef DISABLE_PERFCOUNTERS
2055         mono_perfcounters->loader_appdomains--;
2056 #endif
2057
2058         if (domain == mono_root_domain)
2059                 mono_root_domain = NULL;
2060 }
2061
2062 /**
2063  * mono_domain_get_id:
2064  * @domainid: the ID
2065  *
2066  * Returns: the a domain for a specific domain id.
2067  */
2068 MonoDomain * 
2069 mono_domain_get_by_id (gint32 domainid) 
2070 {
2071         MonoDomain * domain;
2072
2073         mono_appdomains_lock ();
2074         if (domainid < appdomain_list_size)
2075                 domain = appdomains_list [domainid];
2076         else
2077                 domain = NULL;
2078         mono_appdomains_unlock ();
2079
2080         return domain;
2081 }
2082
2083 gint32
2084 mono_domain_get_id (MonoDomain *domain)
2085 {
2086         return domain->domain_id;
2087 }
2088
2089 /*
2090  * mono_domain_alloc:
2091  *
2092  * LOCKING: Acquires the domain lock.
2093  */
2094 gpointer
2095 mono_domain_alloc (MonoDomain *domain, guint size)
2096 {
2097         gpointer res;
2098
2099         mono_domain_lock (domain);
2100 #ifndef DISABLE_PERFCOUNTERS
2101         mono_perfcounters->loader_bytes += size;
2102 #endif
2103         res = mono_mempool_alloc (domain->mp, size);
2104         mono_domain_unlock (domain);
2105
2106         return res;
2107 }
2108
2109 /*
2110  * mono_domain_alloc0:
2111  *
2112  * LOCKING: Acquires the domain lock.
2113  */
2114 gpointer
2115 mono_domain_alloc0 (MonoDomain *domain, guint size)
2116 {
2117         gpointer res;
2118
2119         mono_domain_lock (domain);
2120 #ifndef DISABLE_PERFCOUNTERS
2121         mono_perfcounters->loader_bytes += size;
2122 #endif
2123         res = mono_mempool_alloc0 (domain->mp, size);
2124         mono_domain_unlock (domain);
2125
2126         return res;
2127 }
2128
2129 /*
2130  * mono_domain_code_reserve:
2131  *
2132  * LOCKING: Acquires the domain lock.
2133  */
2134 void*
2135 mono_domain_code_reserve (MonoDomain *domain, int size)
2136 {
2137         gpointer res;
2138
2139         mono_domain_lock (domain);
2140         res = mono_code_manager_reserve (domain->code_mp, size);
2141         mono_domain_unlock (domain);
2142
2143         return res;
2144 }
2145
2146 /*
2147  * mono_domain_code_reserve_align:
2148  *
2149  * LOCKING: Acquires the domain lock.
2150  */
2151 void*
2152 mono_domain_code_reserve_align (MonoDomain *domain, int size, int alignment)
2153 {
2154         gpointer res;
2155
2156         mono_domain_lock (domain);
2157         res = mono_code_manager_reserve_align (domain->code_mp, size, alignment);
2158         mono_domain_unlock (domain);
2159
2160         return res;
2161 }
2162
2163 /*
2164  * mono_domain_code_commit:
2165  *
2166  * LOCKING: Acquires the domain lock.
2167  */
2168 void
2169 mono_domain_code_commit (MonoDomain *domain, void *data, int size, int newsize)
2170 {
2171         mono_domain_lock (domain);
2172         mono_code_manager_commit (domain->code_mp, data, size, newsize);
2173         mono_domain_unlock (domain);
2174 }
2175
2176 #if defined(__native_client_codegen__) && defined(__native_client__)
2177 /*
2178  * Given the temporary buffer (allocated by mono_domain_code_reserve) into which
2179  * we are generating code, return a pointer to the destination in the dynamic 
2180  * code segment into which the code will be copied when mono_domain_code_commit
2181  * is called.
2182  * LOCKING: Acquires the domain lock.
2183  */
2184 void *
2185 nacl_domain_get_code_dest (MonoDomain *domain, void *data)
2186 {
2187         void *dest;
2188         mono_domain_lock (domain);
2189         dest = nacl_code_manager_get_code_dest (domain->code_mp, data);
2190         mono_domain_unlock (domain);
2191         return dest;
2192 }
2193
2194 /* 
2195  * Convenience function which calls mono_domain_code_commit to validate and copy
2196  * the code. The caller sets *buf_base and *buf_size to the start and size of
2197  * the buffer (allocated by mono_domain_code_reserve), and *code_end to the byte
2198  * after the last instruction byte. On return, *buf_base will point to the start
2199  * of the copied in the code segment, and *code_end will point after the end of 
2200  * the copied code.
2201  */
2202 void
2203 nacl_domain_code_validate (MonoDomain *domain, guint8 **buf_base, int buf_size, guint8 **code_end)
2204 {
2205         guint8 *tmp = nacl_domain_get_code_dest (domain, *buf_base);
2206         mono_domain_code_commit (domain, *buf_base, buf_size, *code_end - *buf_base);
2207         *code_end = tmp + (*code_end - *buf_base);
2208         *buf_base = tmp;
2209 }
2210
2211 #else
2212
2213 /* no-op versions of Native Client functions */
2214
2215 void *
2216 nacl_domain_get_code_dest (MonoDomain *domain, void *data)
2217 {
2218         return data;
2219 }
2220
2221 void
2222 nacl_domain_code_validate (MonoDomain *domain, guint8 **buf_base, int buf_size, guint8 **code_end)
2223 {
2224 }
2225
2226 #endif
2227
2228 /*
2229  * mono_domain_code_foreach:
2230  * Iterate over the code thunks of the code manager of @domain.
2231  * 
2232  * The @func callback MUST not take any locks. If it really needs to, it must respect
2233  * the locking rules of the runtime: http://www.mono-project.com/Mono:Runtime:Documentation:ThreadSafety 
2234  * LOCKING: Acquires the domain lock.
2235  */
2236
2237 void
2238 mono_domain_code_foreach (MonoDomain *domain, MonoCodeManagerFunc func, void *user_data)
2239 {
2240         mono_domain_lock (domain);
2241         mono_code_manager_foreach (domain->code_mp, func, user_data);
2242         mono_domain_unlock (domain);
2243 }
2244
2245
2246 void 
2247 mono_context_set (MonoAppContext * new_context)
2248 {
2249         SET_APPCONTEXT (new_context);
2250 }
2251
2252 MonoAppContext * 
2253 mono_context_get (void)
2254 {
2255         return GET_APPCONTEXT ();
2256 }
2257
2258 /* LOCKING: the caller holds the lock for this domain */
2259 void
2260 mono_domain_add_class_static_data (MonoDomain *domain, MonoClass *klass, gpointer data, guint32 *bitmap)
2261 {
2262         /* The first entry in the array is the index of the next free slot
2263          * and the total size of the array
2264          */
2265         int next;
2266         if (domain->static_data_array) {
2267                 int size = GPOINTER_TO_INT (domain->static_data_array [1]);
2268                 next = GPOINTER_TO_INT (domain->static_data_array [0]);
2269                 if (next >= size) {
2270                         /* 'data' is allocated by alloc_fixed */
2271                         gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * (size * 2), MONO_GC_ROOT_DESCR_FOR_FIXED (size * 2));
2272                         mono_gc_memmove (new_array, domain->static_data_array, sizeof (gpointer) * size);
2273                         size *= 2;
2274                         new_array [1] = GINT_TO_POINTER (size);
2275                         mono_gc_free_fixed (domain->static_data_array);
2276                         domain->static_data_array = new_array;
2277                 }
2278         } else {
2279                 int size = 32;
2280                 gpointer *new_array = mono_gc_alloc_fixed (sizeof (gpointer) * size, MONO_GC_ROOT_DESCR_FOR_FIXED (size));
2281                 next = 2;
2282                 new_array [0] = GINT_TO_POINTER (next);
2283                 new_array [1] = GINT_TO_POINTER (size);
2284                 domain->static_data_array = new_array;
2285         }
2286         domain->static_data_array [next++] = data;
2287         domain->static_data_array [0] = GINT_TO_POINTER (next);
2288 }
2289
2290 MonoImage*
2291 mono_get_corlib (void)
2292 {
2293         return mono_defaults.corlib;
2294 }
2295
2296 MonoClass*
2297 mono_get_object_class (void)
2298 {
2299         return mono_defaults.object_class;
2300 }
2301
2302 MonoClass*
2303 mono_get_byte_class (void)
2304 {
2305         return mono_defaults.byte_class;
2306 }
2307
2308 MonoClass*
2309 mono_get_void_class (void)
2310 {
2311         return mono_defaults.void_class;
2312 }
2313
2314 MonoClass*
2315 mono_get_boolean_class (void)
2316 {
2317         return mono_defaults.boolean_class;
2318 }
2319
2320 MonoClass*
2321 mono_get_sbyte_class (void)
2322 {
2323         return mono_defaults.sbyte_class;
2324 }
2325
2326 MonoClass*
2327 mono_get_int16_class (void)
2328 {
2329         return mono_defaults.int16_class;
2330 }
2331
2332 MonoClass*
2333 mono_get_uint16_class (void)
2334 {
2335         return mono_defaults.uint16_class;
2336 }
2337
2338 MonoClass*
2339 mono_get_int32_class (void)
2340 {
2341         return mono_defaults.int32_class;
2342 }
2343
2344 MonoClass*
2345 mono_get_uint32_class (void)
2346 {
2347         return mono_defaults.uint32_class;
2348 }
2349
2350 MonoClass*
2351 mono_get_intptr_class (void)
2352 {
2353         return mono_defaults.int_class;
2354 }
2355
2356 MonoClass*
2357 mono_get_uintptr_class (void)
2358 {
2359         return mono_defaults.uint_class;
2360 }
2361
2362 MonoClass*
2363 mono_get_int64_class (void)
2364 {
2365         return mono_defaults.int64_class;
2366 }
2367
2368 MonoClass*
2369 mono_get_uint64_class (void)
2370 {
2371         return mono_defaults.uint64_class;
2372 }
2373
2374 MonoClass*
2375 mono_get_single_class (void)
2376 {
2377         return mono_defaults.single_class;
2378 }
2379
2380 MonoClass*
2381 mono_get_double_class (void)
2382 {
2383         return mono_defaults.double_class;
2384 }
2385
2386 MonoClass*
2387 mono_get_char_class (void)
2388 {
2389         return mono_defaults.char_class;
2390 }
2391
2392 MonoClass*
2393 mono_get_string_class (void)
2394 {
2395         return mono_defaults.string_class;
2396 }
2397
2398 MonoClass*
2399 mono_get_enum_class (void)
2400 {
2401         return mono_defaults.enum_class;
2402 }
2403
2404 MonoClass*
2405 mono_get_array_class (void)
2406 {
2407         return mono_defaults.array_class;
2408 }
2409
2410 MonoClass*
2411 mono_get_thread_class (void)
2412 {
2413         return mono_defaults.thread_class;
2414 }
2415
2416 MonoClass*
2417 mono_get_exception_class (void)
2418 {
2419         return mono_defaults.exception_class;
2420 }
2421
2422
2423 static char* get_attribute_value (const gchar **attribute_names, 
2424                                         const gchar **attribute_values, 
2425                                         const char *att_name)
2426 {
2427         int n;
2428         for (n=0; attribute_names[n] != NULL; n++) {
2429                 if (strcmp (attribute_names[n], att_name) == 0)
2430                         return g_strdup (attribute_values[n]);
2431         }
2432         return NULL;
2433 }
2434
2435 static void start_element (GMarkupParseContext *context, 
2436                            const gchar         *element_name,
2437                            const gchar        **attribute_names,
2438                            const gchar        **attribute_values,
2439                            gpointer             user_data,
2440                            GError             **error)
2441 {
2442         AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2443         
2444         if (strcmp (element_name, "configuration") == 0) {
2445                 app_config->configuration_count++;
2446                 return;
2447         }
2448         if (strcmp (element_name, "startup") == 0) {
2449                 app_config->startup_count++;
2450                 return;
2451         }
2452         
2453         if (app_config->configuration_count != 1 || app_config->startup_count != 1)
2454                 return;
2455         
2456         if (strcmp (element_name, "requiredRuntime") == 0) {
2457                 app_config->required_runtime = get_attribute_value (attribute_names, attribute_values, "version");
2458         } else if (strcmp (element_name, "supportedRuntime") == 0) {
2459                 char *version = get_attribute_value (attribute_names, attribute_values, "version");
2460                 app_config->supported_runtimes = g_slist_append (app_config->supported_runtimes, version);
2461         }
2462 }
2463
2464 static void end_element   (GMarkupParseContext *context,
2465                            const gchar         *element_name,
2466                            gpointer             user_data,
2467                            GError             **error)
2468 {
2469         AppConfigInfo* app_config = (AppConfigInfo*) user_data;
2470         
2471         if (strcmp (element_name, "configuration") == 0) {
2472                 app_config->configuration_count--;
2473         } else if (strcmp (element_name, "startup") == 0) {
2474                 app_config->startup_count--;
2475         }
2476 }
2477
2478 static const GMarkupParser 
2479 mono_parser = {
2480         start_element,
2481         end_element,
2482         NULL,
2483         NULL,
2484         NULL
2485 };
2486
2487 static AppConfigInfo *
2488 app_config_parse (const char *exe_filename)
2489 {
2490         AppConfigInfo *app_config;
2491         GMarkupParseContext *context;
2492         char *text;
2493         gsize len;
2494         const char *bundled_config;
2495         char *config_filename;
2496
2497         bundled_config = mono_config_string_for_assembly_file (exe_filename);
2498
2499         if (bundled_config) {
2500                 text = g_strdup (bundled_config);
2501                 len = strlen (text);
2502         } else {
2503                 config_filename = g_strconcat (exe_filename, ".config", NULL);
2504
2505                 if (!g_file_get_contents (config_filename, &text, &len, NULL)) {
2506                         g_free (config_filename);
2507                         return NULL;
2508                 }
2509                 g_free (config_filename);
2510         }
2511
2512         app_config = g_new0 (AppConfigInfo, 1);
2513
2514         context = g_markup_parse_context_new (&mono_parser, 0, app_config, NULL);
2515         if (g_markup_parse_context_parse (context, text, len, NULL)) {
2516                 g_markup_parse_context_end_parse (context, NULL);
2517         }
2518         g_markup_parse_context_free (context);
2519         g_free (text);
2520         return app_config;
2521 }
2522
2523 static void 
2524 app_config_free (AppConfigInfo* app_config)
2525 {
2526         char *rt;
2527         GSList *list = app_config->supported_runtimes;
2528         while (list != NULL) {
2529                 rt = (char*)list->data;
2530                 g_free (rt);
2531                 list = g_slist_next (list);
2532         }
2533         g_slist_free (app_config->supported_runtimes);
2534         g_free (app_config->required_runtime);
2535         g_free (app_config);
2536 }
2537
2538
2539 static const MonoRuntimeInfo*
2540 get_runtime_by_version (const char *version)
2541 {
2542         int n;
2543         int max = G_N_ELEMENTS (supported_runtimes);
2544         int vlen;
2545
2546         if (!version)
2547                 return NULL;
2548
2549         for (n=0; n<max; n++) {
2550                 if (strcmp (version, supported_runtimes[n].runtime_version) == 0)
2551                         return &supported_runtimes[n];
2552         }
2553         
2554         vlen = strlen (version);
2555         if (vlen >= 4 && version [1] - '0' >= 4) {
2556                 for (n=0; n<max; n++) {
2557                         if (strncmp (version, supported_runtimes[n].runtime_version, 4) == 0)
2558                                 return &supported_runtimes[n];
2559                 }
2560         }
2561         
2562         return NULL;
2563 }
2564
2565 static void
2566 get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRuntimeInfo** runtimes)
2567 {
2568         AppConfigInfo* app_config;
2569         char *version;
2570         const MonoRuntimeInfo* runtime = NULL;
2571         MonoImage *image = NULL;
2572         
2573         app_config = app_config_parse (exe_file);
2574         
2575         if (app_config != NULL) {
2576                 /* Check supportedRuntime elements, if none is supported, fail.
2577                  * If there are no such elements, look for a requiredRuntime element.
2578                  */
2579                 if (app_config->supported_runtimes != NULL) {
2580                         int n = 0;
2581                         GSList *list = app_config->supported_runtimes;
2582                         while (list != NULL) {
2583                                 version = (char*) list->data;
2584                                 runtime = get_runtime_by_version (version);
2585                                 if (runtime != NULL)
2586                                         runtimes [n++] = runtime;
2587                                 list = g_slist_next (list);
2588                         }
2589                         runtimes [n] = NULL;
2590                         app_config_free (app_config);
2591                         return;
2592                 }
2593                 
2594                 /* Check the requiredRuntime element. This is for 1.0 apps only. */
2595                 if (app_config->required_runtime != NULL) {
2596                         runtimes [0] = get_runtime_by_version (app_config->required_runtime);
2597                         runtimes [1] = NULL;
2598                         app_config_free (app_config);
2599                         return;
2600                 }
2601                 app_config_free (app_config);
2602         }
2603         
2604         /* Look for a runtime with the exact version */
2605         image = mono_assembly_open_from_bundle (exe_file, NULL, FALSE);
2606
2607         if (image == NULL)
2608                 image = mono_image_open (exe_file, NULL);
2609
2610         if (image == NULL) {
2611                 /* The image is wrong or the file was not found. In this case return
2612                  * a default runtime and leave to the initialization method the work of
2613                  * reporting the error.
2614                  */
2615                 runtimes [0] = get_runtime_by_version (DEFAULT_RUNTIME_VERSION);
2616                 runtimes [1] = NULL;
2617                 return;
2618         }
2619
2620         *exe_image = image;
2621
2622         runtimes [0] = get_runtime_by_version (image->version);
2623         runtimes [1] = NULL;
2624 }
2625
2626
2627 /**
2628  * mono_get_runtime_info:
2629  *
2630  * Returns: the version of the current runtime instance.
2631  */
2632 const MonoRuntimeInfo*
2633 mono_get_runtime_info (void)
2634 {
2635         return current_runtime;
2636 }
2637
2638 gchar *
2639 mono_debugger_check_runtime_version (const char *filename)
2640 {
2641         const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
2642         const MonoRuntimeInfo *rinfo;
2643         MonoImage *image;
2644
2645         get_runtimes_from_exe (filename, &image, runtimes);
2646         rinfo = runtimes [0];
2647
2648         if (!rinfo)
2649                 return g_strdup_printf ("Cannot get runtime version from assembly `%s'", filename);
2650
2651         if (rinfo != current_runtime)
2652                 return g_strdup_printf ("The Mono Debugger is currently using the `%s' runtime, but "
2653                                         "the assembly `%s' requires version `%s'", current_runtime->runtime_version,
2654                                         filename, rinfo->runtime_version);
2655
2656         return NULL;
2657 }
2658
2659 /**
2660  * mono_framework_version:
2661  *
2662  * Return the major version of the framework curently executing.
2663  */
2664 int
2665 mono_framework_version (void)
2666 {
2667         return current_runtime->framework_version [0] - '0';
2668 }