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