2003-04-22 Dietmar Maurer <dietmar@ximian.com>
[mono.git] / mono / metadata / domain.c
1
2 /*
3  * domain.c: MonoDomain functions
4  *
5  * Author:
6  *      Dietmar Maurer (dietmar@ximian.com)
7  *      Patrik Torstensson
8  *
9  * (C) 2001 Ximian, Inc.
10  */
11
12 #include <config.h>
13 #include <glib.h>
14 #include <string.h>
15
16 #include <mono/os/gc_wrapper.h>
17
18 #include <mono/metadata/object.h>
19 #include <mono/metadata/appdomain.h>
20 #include <mono/metadata/assembly.h>
21 #include <mono/metadata/exception.h>
22 #include <mono/metadata/cil-coff.h>
23
24 static guint32 appdomain_thread_id = 0;
25 static guint32 context_thread_id = 0;
26
27 static gint32 appdomain_id_counter = 0;
28
29 static MonoGHashTable * appdomains_list = NULL;
30
31 MonoDomain *mono_root_domain = NULL;
32
33 static MonoJitInfoTable *
34 mono_jit_info_table_new (void)
35 {
36         return g_array_new (FALSE, FALSE, sizeof (gpointer));
37 }
38
39 static void
40 mono_jit_info_table_free (MonoJitInfoTable *table)
41 {
42         g_array_free (table, TRUE);
43 }
44
45 static int
46 mono_jit_info_table_index (MonoJitInfoTable *table, char *addr)
47 {
48         int left = 0, right = table->len;
49
50         while (left < right) {
51                 int pos = (left + right) / 2;
52                 MonoJitInfo *ji = g_array_index (table, gpointer, pos);
53                 char *start = ji->code_start;
54                 char *end = start + ji->code_size;
55
56                 if (addr < start)
57                         right = pos;
58                 else if (addr >= end) 
59                         left = pos + 1;
60                 else
61                         return pos;
62         }
63
64         return left;
65 }
66
67 MonoJitInfo *
68 mono_jit_info_table_find (MonoDomain *domain, char *addr)
69 {
70         MonoJitInfoTable *table = domain->jit_info_table;
71         int left = 0, right = table->len;
72
73         while (left < right) {
74                 int pos = (left + right) / 2;
75                 MonoJitInfo *ji = g_array_index (table, gpointer, pos);
76                 char *start = ji->code_start;
77                 char *end = start + ji->code_size;
78
79                 if (addr < start)
80                         right = pos;
81                 else if (addr >= end) 
82                         left = pos + 1;
83                 else
84                         return ji;
85         }
86
87         /* maybe irt is shared code, so we also search in the root domain */
88         if (domain != mono_root_domain)
89                 return mono_jit_info_table_find (mono_root_domain, addr);
90
91         return NULL;
92 }
93
94 void
95 mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
96 {
97         MonoJitInfoTable *table = domain->jit_info_table;
98         gpointer start = ji->code_start;
99         int pos = mono_jit_info_table_index (table, start);
100
101         g_array_insert_val (table, pos, ji);
102 }
103
104 static int
105 ldstr_hash (const char* str)
106 {
107         guint len, h;
108         const char *end;
109         len = mono_metadata_decode_blob_size (str, &str) - 1;
110         end = str + len;
111         /* if len == 0 *str will point to the mark byte */
112         h = len? *str: 0;
113         /*
114          * FIXME: The distribution may not be so nice with lots of
115          * null chars in the string.
116          */
117         for (str += 1; str < end; str++)
118                 h = (h << 5) - h + *str;
119         return h;
120 }
121
122 static gboolean
123 ldstr_equal (const char *str1, const char *str2) {
124         int len, len2;
125         len = mono_metadata_decode_blob_size (str1, NULL) - 1;
126         len2 = mono_metadata_decode_blob_size (str2, NULL) - 1;
127         if (len != len2)
128                 return 0;
129         return memcmp (str1, str2, len) == 0;
130 }
131
132 static gboolean
133 mono_string_equal (MonoString *s1, MonoString *s2)
134 {
135         int l1 = mono_string_length (s1);
136         int l2 = mono_string_length (s2);
137
138         if (l1 != l2)
139                 return FALSE;
140
141         return memcmp (mono_string_chars (s1), mono_string_chars (s2), l1) == 0; 
142 }
143
144 static guint
145 mono_string_hash (MonoString *s)
146 {
147         const guint16 *p = mono_string_chars (s);
148         int i, len = mono_string_length (s);
149         guint h = 0;
150
151         for (i = 0; i < len; i++) {
152                 h = (h << 5) - h + *p;
153                 p++;
154         }
155
156         return h;       
157 }
158
159 #if HAVE_BOEHM_GC
160 static void
161 domain_finalizer (void *obj, void *data) {
162         g_print ("domain finalized\n");
163 }
164 #endif
165
166 MonoDomain *
167 mono_domain_create (void)
168 {
169         MonoDomain *domain;
170
171 #if HAVE_BOEHM_GC
172         domain = GC_MALLOC (sizeof (MonoDomain));
173         GC_REGISTER_FINALIZER (domain, domain_finalizer, NULL, NULL, NULL);
174 #else
175         domain = g_new0 (MonoDomain, 1);
176 #endif
177         domain->domain = NULL;
178         domain->setup = NULL;
179         domain->friendly_name = NULL;
180         domain->search_path = NULL;
181
182         domain->mp = mono_mempool_new ();
183         domain->code_mp = mono_mempool_new ();
184         domain->env = mono_g_hash_table_new ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal);
185         domain->assemblies = g_hash_table_new (g_str_hash, g_str_equal);
186         domain->class_vtable_hash = mono_g_hash_table_new (NULL, NULL);
187         domain->proxy_vtable_hash = mono_g_hash_table_new (NULL, NULL);
188         domain->static_data_hash = mono_g_hash_table_new (NULL, NULL);
189         domain->jit_code_hash = g_hash_table_new (NULL, NULL);
190         domain->ldstr_table = mono_g_hash_table_new ((GHashFunc)ldstr_hash, (GCompareFunc)ldstr_equal);
191         domain->jit_info_table = mono_jit_info_table_new ();
192         domain->domain_id = InterlockedIncrement (&appdomain_id_counter);
193
194         InitializeCriticalSection (&domain->lock);
195
196         mono_g_hash_table_insert(appdomains_list, GINT_TO_POINTER(domain->domain_id), domain);
197
198         return domain;
199 }
200
201 /**
202  * mono_init:
203  * 
204  * Creates the initial application domain and initializes the mono_defaults
205  * structure.
206  * This function is guaranteed to not run any IL code.
207  *
208  * Returns: the initial domain.
209  */
210 MonoDomain *
211 mono_init (const char *filename)
212 {
213         static MonoDomain *domain = NULL;
214         MonoAssembly *ass;
215         MonoImageOpenStatus status = MONO_IMAGE_OK;
216         MonoAssemblyName corlib_aname;
217
218         if (domain)
219                 g_assert_not_reached ();
220
221         appdomain_thread_id = TlsAlloc ();
222         context_thread_id = TlsAlloc ();
223
224         // FIXME: When should we release this memory?
225         appdomains_list = mono_g_hash_table_new (g_direct_hash, g_direct_equal);
226
227         domain = mono_domain_create ();
228         mono_root_domain = domain;
229
230         TlsSetValue (appdomain_thread_id, domain);
231
232         /* find the corlib */
233         corlib_aname.name = "corlib";
234         ass = mono_assembly_load (&corlib_aname, NULL, &status);
235         if ((status != MONO_IMAGE_OK) || (ass == NULL)) {
236                 switch (status){
237                 case MONO_IMAGE_ERROR_ERRNO:
238                         g_print ("The assembly corlib.dll was not found or could not be loaded.\n");
239                         g_print ("It should have been installed in the `%s' directory.\n", MONO_ASSEMBLIES);
240                         break;
241                 case MONO_IMAGE_IMAGE_INVALID:
242                         g_print ("The file %s/corlib.dll is an invalid CIL image\n", MONO_ASSEMBLIES);
243                         break;
244                 case MONO_IMAGE_MISSING_ASSEMBLYREF:
245                         g_print ("Minning assembly reference in %s/corlib.dll\n", MONO_ASSEMBLIES);
246                         break;
247                 case MONO_IMAGE_OK:
248                         /* to suppress compiler warning */
249                         break;
250                 }
251                 
252                 exit (1);
253         }
254         mono_defaults.corlib = ass->image;
255
256         mono_defaults.object_class = mono_class_from_name (
257                 mono_defaults.corlib, "System", "Object");
258         g_assert (mono_defaults.object_class != 0);
259
260         mono_defaults.void_class = mono_class_from_name (
261                 mono_defaults.corlib, "System", "Void");
262         g_assert (mono_defaults.void_class != 0);
263
264         mono_defaults.boolean_class = mono_class_from_name (
265                 mono_defaults.corlib, "System", "Boolean");
266         g_assert (mono_defaults.boolean_class != 0);
267
268         mono_defaults.byte_class = mono_class_from_name (
269                 mono_defaults.corlib, "System", "Byte");
270         g_assert (mono_defaults.byte_class != 0);
271
272         mono_defaults.sbyte_class = mono_class_from_name (
273                 mono_defaults.corlib, "System", "SByte");
274         g_assert (mono_defaults.sbyte_class != 0);
275
276         mono_defaults.int16_class = mono_class_from_name (
277                 mono_defaults.corlib, "System", "Int16");
278         g_assert (mono_defaults.int16_class != 0);
279
280         mono_defaults.uint16_class = mono_class_from_name (
281                 mono_defaults.corlib, "System", "UInt16");
282         g_assert (mono_defaults.uint16_class != 0);
283
284         mono_defaults.int32_class = mono_class_from_name (
285                 mono_defaults.corlib, "System", "Int32");
286         g_assert (mono_defaults.int32_class != 0);
287
288         mono_defaults.uint32_class = mono_class_from_name (
289                 mono_defaults.corlib, "System", "UInt32");
290         g_assert (mono_defaults.uint32_class != 0);
291
292         mono_defaults.uint_class = mono_class_from_name (
293                 mono_defaults.corlib, "System", "UIntPtr");
294         g_assert (mono_defaults.uint_class != 0);
295
296         mono_defaults.int_class = mono_class_from_name (
297                 mono_defaults.corlib, "System", "IntPtr");
298         g_assert (mono_defaults.int_class != 0);
299
300         mono_defaults.int64_class = mono_class_from_name (
301                 mono_defaults.corlib, "System", "Int64");
302         g_assert (mono_defaults.int64_class != 0);
303
304         mono_defaults.uint64_class = mono_class_from_name (
305                 mono_defaults.corlib, "System", "UInt64");
306         g_assert (mono_defaults.uint64_class != 0);
307
308         mono_defaults.single_class = mono_class_from_name (
309                 mono_defaults.corlib, "System", "Single");
310         g_assert (mono_defaults.single_class != 0);
311
312         mono_defaults.double_class = mono_class_from_name (
313                 mono_defaults.corlib, "System", "Double");
314         g_assert (mono_defaults.double_class != 0);
315
316         mono_defaults.char_class = mono_class_from_name (
317                 mono_defaults.corlib, "System", "Char");
318         g_assert (mono_defaults.char_class != 0);
319
320         mono_defaults.string_class = mono_class_from_name (
321                 mono_defaults.corlib, "System", "String");
322         g_assert (mono_defaults.string_class != 0);
323
324         mono_defaults.enum_class = mono_class_from_name (
325                 mono_defaults.corlib, "System", "Enum");
326         g_assert (mono_defaults.enum_class != 0);
327
328         mono_defaults.array_class = mono_class_from_name (
329                 mono_defaults.corlib, "System", "Array");
330         g_assert (mono_defaults.array_class != 0);
331
332         mono_defaults.delegate_class = mono_class_from_name (
333                 mono_defaults.corlib, "System", "Delegate");
334         g_assert (mono_defaults.delegate_class != 0 );
335
336         mono_defaults.multicastdelegate_class = mono_class_from_name (
337                 mono_defaults.corlib, "System", "MulticastDelegate");
338         g_assert (mono_defaults.multicastdelegate_class != 0 );
339
340         mono_defaults.asyncresult_class = mono_class_from_name (
341                 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", 
342                 "AsyncResult");
343         g_assert (mono_defaults.asyncresult_class != 0 );
344
345         mono_defaults.waithandle_class = mono_class_from_name (
346                 mono_defaults.corlib, "System.Threading", "WaitHandle");
347         g_assert (mono_defaults.waithandle_class != 0 );
348
349         mono_defaults.typehandle_class = mono_class_from_name (
350                 mono_defaults.corlib, "System", "RuntimeTypeHandle");
351         g_assert (mono_defaults.typehandle_class != 0);
352
353         mono_defaults.methodhandle_class = mono_class_from_name (
354                 mono_defaults.corlib, "System", "RuntimeMethodHandle");
355         g_assert (mono_defaults.methodhandle_class != 0);
356
357         mono_defaults.fieldhandle_class = mono_class_from_name (
358                 mono_defaults.corlib, "System", "RuntimeFieldHandle");
359         g_assert (mono_defaults.fieldhandle_class != 0);
360
361         mono_defaults.monotype_class = mono_class_from_name (
362                 mono_defaults.corlib, "System", "MonoType");
363         g_assert (mono_defaults.monotype_class != 0);
364
365         mono_defaults.exception_class = mono_class_from_name (
366                 mono_defaults.corlib, "System", "Exception");
367         g_assert (mono_defaults.exception_class != 0);
368
369         mono_defaults.threadabortexception_class = mono_class_from_name (
370                 mono_defaults.corlib, "System.Threading", "ThreadAbortException");
371         g_assert (mono_defaults.threadabortexception_class != 0);
372
373         mono_defaults.thread_class = mono_class_from_name (
374                 mono_defaults.corlib, "System.Threading", "Thread");
375         g_assert (mono_defaults.thread_class != 0);
376
377         mono_defaults.appdomain_class = mono_class_from_name (
378                 mono_defaults.corlib, "System", "AppDomain");
379         g_assert (mono_defaults.appdomain_class != 0);
380
381         mono_defaults.transparent_proxy_class = mono_class_from_name (
382                 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "TransparentProxy");
383         g_assert (mono_defaults.transparent_proxy_class != 0);
384
385         mono_defaults.real_proxy_class = mono_class_from_name (
386                 mono_defaults.corlib, "System.Runtime.Remoting.Proxies", "RealProxy");
387         g_assert (mono_defaults.real_proxy_class != 0);
388
389         mono_defaults.mono_method_message_class = mono_class_from_name (
390                 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", "MonoMethodMessage");
391         g_assert (mono_defaults.mono_method_message_class != 0);
392
393         mono_defaults.field_info_class = mono_class_from_name (
394                 mono_defaults.corlib, "System.Reflection", "FieldInfo");
395         g_assert (mono_defaults.field_info_class != 0);
396
397         mono_defaults.method_info_class = mono_class_from_name (
398                 mono_defaults.corlib, "System.Reflection", "MethodInfo");
399         g_assert (mono_defaults.method_info_class != 0);
400
401         mono_defaults.stringbuilder_class = mono_class_from_name (
402                 mono_defaults.corlib, "System.Text", "StringBuilder");
403         g_assert (mono_defaults.stringbuilder_class != 0);
404
405         mono_defaults.math_class = mono_class_from_name (
406                 mono_defaults.corlib, "System", "Math");
407         g_assert (mono_defaults.math_class != 0);
408
409         mono_defaults.stack_frame_class = mono_class_from_name (
410                 mono_defaults.corlib, "System.Diagnostics", "StackFrame");
411         g_assert (mono_defaults.stack_frame_class != 0);
412
413         mono_defaults.stack_trace_class = mono_class_from_name (
414                 mono_defaults.corlib, "System.Diagnostics", "StackTrace");
415         g_assert (mono_defaults.stack_trace_class != 0);
416
417         mono_defaults.marshal_class = mono_class_from_name (
418                 mono_defaults.corlib, "System.Runtime.InteropServices", "Marshal");
419         g_assert (mono_defaults.marshal_class != 0);
420
421         mono_defaults.iserializeable_class = mono_class_from_name (
422                 mono_defaults.corlib, "System.Runtime.Serialization", "ISerializable");
423         g_assert (mono_defaults.iserializeable_class != 0);
424
425         mono_defaults.serializationinfo_class = mono_class_from_name (
426                 mono_defaults.corlib, "System.Runtime.Serialization", "SerializationInfo");
427         g_assert (mono_defaults.serializationinfo_class != 0);
428
429         mono_defaults.streamingcontext_class = mono_class_from_name (
430                 mono_defaults.corlib, "System.Runtime.Serialization", "StreamingContext");
431         g_assert (mono_defaults.streamingcontext_class != 0);
432
433         mono_defaults.typed_reference_class =  mono_class_from_name (
434                 mono_defaults.corlib, "System", "TypedReference");
435         g_assert (mono_defaults.typed_reference_class != 0);
436
437         mono_defaults.marshalbyrefobject_class =  mono_class_from_name (
438                 mono_defaults.corlib, "System", "MarshalByRefObject");
439         g_assert (mono_defaults.marshalbyrefobject_class != 0);
440
441         mono_defaults.monitor_class =  mono_class_from_name (
442                 mono_defaults.corlib, "System.Threading", "Monitor");
443         g_assert (mono_defaults.monitor_class != 0);
444
445         domain->friendly_name = g_path_get_basename (filename);
446
447         return domain;
448 }
449
450 /**
451  * mono_domain_get:
452  *
453  * Returns the current domain.
454  */
455 inline MonoDomain *
456 mono_domain_get ()
457 {
458         return ((MonoDomain *)TlsGetValue (appdomain_thread_id));
459 }
460
461 /**
462  * mono_domain_set:
463  * @domain: the new domain
464  *
465  * Sets the current domain to @domain.
466  */
467 inline void
468 mono_domain_set (MonoDomain *domain)
469 {
470         TlsSetValue (appdomain_thread_id, domain);
471         TlsSetValue (context_thread_id, domain->default_context);
472 }
473
474 typedef struct {
475         MonoDomainFunc func;
476         gpointer user_data;
477 } DomainInfo;
478
479 static void
480 foreach_domain (gconstpointer key, gconstpointer data, gpointer user_data)
481 {
482         DomainInfo *dom_info = user_data;
483
484         dom_info->func ((MonoDomain*)data, dom_info->user_data);
485 }
486
487 void
488 mono_domain_foreach (MonoDomainFunc func, gpointer user_data)
489 {
490         DomainInfo dom_info;
491
492         dom_info.func = func;
493         dom_info.user_data = user_data;
494         mono_g_hash_table_foreach (appdomains_list, foreach_domain, &dom_info);
495 }
496
497 /**
498  * mono_domain_assembly_open:
499  * @domain: the application domain
500  * @name: file name of the assembly
501  *
502  * fixme: maybe we should integrate this with mono_assembly_open ??
503  */
504 MonoAssembly *
505 mono_domain_assembly_open (MonoDomain *domain, const char *name)
506 {
507         MonoAssembly *ass;
508
509         if ((ass = g_hash_table_lookup (domain->assemblies, name)))
510                 return ass;
511
512         if (!(ass = mono_assembly_open (name, NULL)))
513                 return NULL;
514
515         return ass;
516 }
517
518 static void
519 remove_assembly (gpointer key, gpointer value, gpointer user_data)
520 {
521         mono_assembly_close ((MonoAssembly *)value);
522 }
523
524 void
525 mono_domain_unload (MonoDomain *domain, gboolean force)
526 {
527         if ((domain == mono_root_domain) && !force) {
528                 g_warning ("cant unload root domain");
529                 return;
530         }
531
532         mono_g_hash_table_remove(appdomains_list, GINT_TO_POINTER(domain->domain_id));
533         
534         g_free (domain->friendly_name);
535         g_hash_table_foreach (domain->assemblies, remove_assembly, NULL);
536
537         mono_g_hash_table_destroy (domain->env);
538         g_hash_table_destroy (domain->assemblies);
539         mono_g_hash_table_destroy (domain->class_vtable_hash);
540         mono_g_hash_table_destroy (domain->proxy_vtable_hash);
541         mono_g_hash_table_destroy (domain->static_data_hash);
542         g_hash_table_destroy (domain->jit_code_hash);
543         mono_g_hash_table_destroy (domain->ldstr_table);
544         mono_jit_info_table_free (domain->jit_info_table);
545         mono_mempool_destroy (domain->mp);
546         mono_mempool_destroy (domain->code_mp);
547         DeleteCriticalSection (&domain->lock);
548         domain->setup = NULL;
549
550         /* FIXME: anything else required ? */
551
552 #if HAVE_BOEHM_GC
553 #else
554         g_free (domain);
555 #endif
556
557         if ((domain == mono_root_domain))
558                 mono_root_domain = NULL;
559 }
560
561 /**
562  * mono_domain_get_id:
563  *
564  * Returns the a domain for a specific domain id.
565  */
566 MonoDomain * 
567 mono_domain_get_by_id (gint32 domainid) 
568 {
569         MonoDomain * domain;
570
571         if ((domain = mono_g_hash_table_lookup(appdomains_list, GINT_TO_POINTER(domainid)))) 
572                 return domain;
573
574         return NULL;
575 }
576
577 void 
578 mono_context_set (MonoAppContext * new_context)
579 {
580         TlsSetValue (context_thread_id, new_context);
581 }
582
583 MonoAppContext * 
584 mono_context_get ()
585 {
586         return ((MonoAppContext *)TlsGetValue (context_thread_id));
587 }