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