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