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