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