85fd2708111b57412ebf56997d5a28e1e9a7609a
[mono.git] / mono / metadata / dynamic-image.c
1 /**
2  * \file
3  * Images created at runtime.
4  *   
5  * 
6  * Author:
7  *   Paolo Molaro (lupus@ximian.com)
8  *
9  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11  * Copyright 2011 Rodrigo Kumpera
12  * Copyright 2016 Microsoft
13  *
14  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
15  */
16
17 #include <config.h>
18 #include <glib.h>
19 #include "mono/metadata/object.h"
20 #include "mono/metadata/dynamic-image-internals.h"
21 #include "mono/metadata/dynamic-stream-internals.h"
22 #include "mono/metadata/gc-internals.h"
23 #include "mono/metadata/metadata-internals.h"
24 #include "mono/metadata/profiler-private.h"
25 #include "mono/metadata/reflection-internals.h"
26 #include "mono/metadata/sre-internals.h"
27 #include "mono/utils/checked-build.h"
28 #include "mono/utils/mono-error-internals.h"
29 #include "mono/utils/mono-os-mutex.h"
30
31 const unsigned char table_sizes [MONO_TABLE_NUM] = {
32         MONO_MODULE_SIZE,
33         MONO_TYPEREF_SIZE,
34         MONO_TYPEDEF_SIZE,
35         0,
36         MONO_FIELD_SIZE,
37         0,
38         MONO_METHOD_SIZE,
39         0,
40         MONO_PARAM_SIZE,
41         MONO_INTERFACEIMPL_SIZE,
42         MONO_MEMBERREF_SIZE,    /* 0x0A */
43         MONO_CONSTANT_SIZE,
44         MONO_CUSTOM_ATTR_SIZE,
45         MONO_FIELD_MARSHAL_SIZE,
46         MONO_DECL_SECURITY_SIZE,
47         MONO_CLASS_LAYOUT_SIZE,
48         MONO_FIELD_LAYOUT_SIZE, /* 0x10 */
49         MONO_STAND_ALONE_SIGNATURE_SIZE,
50         MONO_EVENT_MAP_SIZE,
51         0,
52         MONO_EVENT_SIZE,
53         MONO_PROPERTY_MAP_SIZE,
54         0,
55         MONO_PROPERTY_SIZE,
56         MONO_METHOD_SEMA_SIZE,
57         MONO_METHODIMPL_SIZE,
58         MONO_MODULEREF_SIZE,    /* 0x1A */
59         MONO_TYPESPEC_SIZE,
60         MONO_IMPLMAP_SIZE,      
61         MONO_FIELD_RVA_SIZE,
62         0,
63         0,
64         MONO_ASSEMBLY_SIZE,     /* 0x20 */
65         MONO_ASSEMBLY_PROCESSOR_SIZE,
66         MONO_ASSEMBLYOS_SIZE,
67         MONO_ASSEMBLYREF_SIZE,
68         MONO_ASSEMBLYREFPROC_SIZE,
69         MONO_ASSEMBLYREFOS_SIZE,
70         MONO_FILE_SIZE,
71         MONO_EXP_TYPE_SIZE,
72         MONO_MANIFEST_SIZE,
73         MONO_NESTED_CLASS_SIZE,
74
75         MONO_GENERICPARAM_SIZE, /* 0x2A */
76         MONO_METHODSPEC_SIZE,
77         MONO_GENPARCONSTRAINT_SIZE
78
79 };
80
81 // The dynamic images list is only needed to support the mempool reference tracking feature in checked-build.
82 static GPtrArray *dynamic_images;
83 static mono_mutex_t dynamic_images_mutex;
84
85 static inline void
86 dynamic_images_lock (void)
87 {
88         mono_os_mutex_lock (&dynamic_images_mutex);
89 }
90
91 static inline void
92 dynamic_images_unlock (void)
93 {
94         mono_os_mutex_unlock (&dynamic_images_mutex);
95 }
96
97 void
98 mono_dynamic_images_init (void)
99 {
100         mono_os_mutex_init (&dynamic_images_mutex);
101 }
102
103 #ifndef DISABLE_REFLECTION_EMIT
104 static void
105 string_heap_init (MonoDynamicStream *sh)
106 {
107         mono_dynstream_init (sh);
108 }
109 #endif
110
111 #ifndef DISABLE_REFLECTION_EMIT
112 static int
113 mono_blob_entry_hash (const char* str)
114 {
115         MONO_REQ_GC_NEUTRAL_MODE;
116
117         guint len, h;
118         const char *end;
119         len = mono_metadata_decode_blob_size (str, &str);
120         if (len > 0) {
121                 end = str + len;
122                 h = *str;
123                 for (str += 1; str < end; str++)
124                         h = (h << 5) - h + *str;
125                 return h;
126         } else {
127                 return 0;
128         }
129 }
130
131 static gboolean
132 mono_blob_entry_equal (const char *str1, const char *str2) {
133         MONO_REQ_GC_NEUTRAL_MODE;
134
135         int len, len2;
136         const char *end1;
137         const char *end2;
138         len = mono_metadata_decode_blob_size (str1, &end1);
139         len2 = mono_metadata_decode_blob_size (str2, &end2);
140         if (len != len2)
141                 return 0;
142         return memcmp (end1, end2, len) == 0;
143 }
144 #endif
145
146
147 /**
148  * mono_find_dynamic_image_owner:
149  *
150  * Find the dynamic image, if any, which a given pointer is located in the memory of.
151  */
152 MonoImage *
153 mono_find_dynamic_image_owner (void *ptr)
154 {
155         MonoImage *owner = NULL;
156         int i;
157
158         dynamic_images_lock ();
159
160         if (dynamic_images)
161         {
162                 for (i = 0; !owner && i < dynamic_images->len; ++i) {
163                         MonoImage *image = (MonoImage *)g_ptr_array_index (dynamic_images, i);
164                         if (mono_mempool_contains_addr (image->mempool, ptr))
165                                 owner = image;
166                 }
167         }
168
169         dynamic_images_unlock ();
170
171         return owner;
172 }
173
174 static inline void
175 dynamic_image_lock (MonoDynamicImage *image)
176 {
177         MONO_ENTER_GC_SAFE;
178         mono_image_lock ((MonoImage*)image);
179         MONO_EXIT_GC_SAFE;
180 }
181
182 static inline void
183 dynamic_image_unlock (MonoDynamicImage *image)
184 {
185         mono_image_unlock ((MonoImage*)image);
186 }
187
188 #ifndef DISABLE_REFLECTION_EMIT
189 /*
190  * mono_dynamic_image_register_token:
191  *
192  *   Register the TOKEN->OBJ mapping in the mapping table in ASSEMBLY. This is required for
193  * the Module.ResolveXXXToken () methods to work.
194  */
195 void
196 mono_dynamic_image_register_token (MonoDynamicImage *assembly, guint32 token, MonoObjectHandle obj, int how_collide)
197 {
198         MONO_REQ_GC_UNSAFE_MODE;
199
200         g_assert (!MONO_HANDLE_IS_NULL (obj));
201         g_assert (strcmp (mono_handle_class (obj)->name, "EnumBuilder"));
202         dynamic_image_lock (assembly);
203         MonoObject *prev = (MonoObject *)mono_g_hash_table_lookup (assembly->tokens, GUINT_TO_POINTER (token));
204         if (prev) {
205                 switch (how_collide) {
206                 case MONO_DYN_IMAGE_TOK_NEW:
207                         g_assert_not_reached ();
208                 case MONO_DYN_IMAGE_TOK_SAME_OK:
209                         g_assert (prev == MONO_HANDLE_RAW (obj));
210                         break;
211                 case MONO_DYN_IMAGE_TOK_REPLACE:
212                         break;
213                 default:
214                         g_assert_not_reached ();
215                 }
216         }
217         mono_g_hash_table_insert (assembly->tokens, GUINT_TO_POINTER (token), MONO_HANDLE_RAW (obj));
218         dynamic_image_unlock (assembly);
219 }
220 #else
221 void
222 mono_dynamic_image_register_token (MonoDynamicImage *assembly, guint32 token, MonoObjectHandle obj, int how_collide)
223 {
224 }
225 #endif
226
227 static MonoObject*
228 lookup_dyn_token (MonoDynamicImage *assembly, guint32 token)
229 {
230         MONO_REQ_GC_UNSAFE_MODE;
231
232         MonoObject *obj;
233
234         dynamic_image_lock (assembly);
235         obj = (MonoObject *)mono_g_hash_table_lookup (assembly->tokens, GUINT_TO_POINTER (token));
236         dynamic_image_unlock (assembly);
237
238         return obj;
239 }
240
241 #ifndef DISABLE_REFLECTION_EMIT
242 MonoObjectHandle
243 mono_dynamic_image_get_registered_token (MonoDynamicImage *dynimage, guint32 token, MonoError *error)
244 {
245         error_init (error);
246         return MONO_HANDLE_NEW (MonoObject, lookup_dyn_token (dynimage, token));
247 }
248 #else /* DISABLE_REFLECTION_EMIT */
249 MonoObjectHandle
250 mono_dynamic_image_get_registered_token (MonoDynamicImage *dynimage, guint32 token, MonoError *error)
251 {
252         g_assert_not_reached ();
253         return NULL_HANDLE;
254 }
255 #endif
256
257 /**
258  * 
259  * mono_dynamic_image_is_valid_token:
260  * 
261  * Returns TRUE if token is valid in the given image.
262  * 
263  */
264 gboolean
265 mono_dynamic_image_is_valid_token (MonoDynamicImage *image, guint32 token)
266 {
267         return lookup_dyn_token (image, token) != NULL;
268 }
269
270 #ifndef DISABLE_REFLECTION_EMIT
271
272 #endif /* DISABLE_REFLECTION_EMIT */
273
274 #ifndef DISABLE_REFLECTION_EMIT
275 /**
276  * mono_reflection_lookup_dynamic_token:
277  *
278  * Finish the Builder object pointed to by TOKEN and return the corresponding
279  * runtime structure. If HANDLE_CLASS is not NULL, it is set to the class required by 
280  * mono_ldtoken. If valid_token is TRUE, assert if it is not found in the token->object
281  * mapping table.
282  *
283  * LOCKING: Take the loader lock
284  */
285 gpointer
286 mono_reflection_lookup_dynamic_token (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context, MonoError *error)
287 {
288         MonoDynamicImage *assembly = (MonoDynamicImage*)image;
289         MonoObject *obj;
290         MonoClass *klass;
291
292         error_init (error);
293         
294         obj = lookup_dyn_token (assembly, token);
295         if (!obj) {
296                 if (valid_token)
297                         g_error ("Could not find required dynamic token 0x%08x", token);
298                 else {
299                         mono_error_set_execution_engine (error, "Could not find dynamic token 0x%08x", token);
300                         return NULL;
301                 }
302         }
303
304         if (!handle_class)
305                 handle_class = &klass;
306         gpointer result = mono_reflection_resolve_object (image, obj, handle_class, context, error);
307         return result;
308 }
309 #else /* DISABLE_REFLECTION_EMIT */
310 gpointer
311 mono_reflection_lookup_dynamic_token (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context, MonoError *error)
312 {
313         error_init (error);
314         return NULL;
315 }
316 #endif /* DISABLE_REFLECTION_EMIT */
317
318 #ifndef DISABLE_REFLECTION_EMIT
319 MonoDynamicImage*
320 mono_dynamic_image_create (MonoDynamicAssembly *assembly, char *assembly_name, char *module_name)
321 {
322         static const guchar entrycode [16] = {0xff, 0x25, 0};
323         MonoDynamicImage *image;
324         int i;
325
326         const char *version;
327
328         if (!strcmp (mono_get_runtime_info ()->framework_version, "2.1"))
329                 version = "v2.0.50727"; /* HACK: SL 2 enforces the .net 2 metadata version */
330         else
331                 version = mono_get_runtime_info ()->runtime_version;
332
333         image = g_new0 (MonoDynamicImage, 1);
334
335         MONO_PROFILER_RAISE (image_loading, (&image->image));
336         
337         /*g_print ("created image %p\n", image);*/
338         /* keep in sync with image.c */
339         image->image.name = assembly_name;
340         image->image.assembly_name = image->image.name; /* they may be different */
341         image->image.module_name = module_name;
342         image->image.version = g_strdup (version);
343         image->image.md_version_major = 1;
344         image->image.md_version_minor = 1;
345         image->image.dynamic = TRUE;
346
347         image->image.references = g_new0 (MonoAssembly*, 1);
348         image->image.references [0] = NULL;
349
350         mono_image_init (&image->image);
351
352         image->token_fixups = mono_g_hash_table_new_type ((GHashFunc)mono_object_hash, NULL, MONO_HASH_KEY_GC, MONO_ROOT_SOURCE_REFLECTION, "dynamic module token fixups table");
353         image->method_to_table_idx = g_hash_table_new (NULL, NULL);
354         image->field_to_table_idx = g_hash_table_new (NULL, NULL);
355         image->method_aux_hash = g_hash_table_new (NULL, NULL);
356         image->vararg_aux_hash = g_hash_table_new (NULL, NULL);
357         image->handleref = g_hash_table_new (NULL, NULL);
358         image->handleref_managed = mono_g_hash_table_new_type ((GHashFunc)mono_object_hash, NULL, MONO_HASH_KEY_GC, MONO_ROOT_SOURCE_REFLECTION, "dynamic module reference-to-token table");
359         image->tokens = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_REFLECTION, "dynamic module tokens table");
360         image->generic_def_objects = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_REFLECTION, "dynamic module generic definitions table");
361         image->typespec = g_hash_table_new ((GHashFunc)mono_metadata_type_hash, (GCompareFunc)mono_metadata_type_equal);
362         image->typeref = g_hash_table_new ((GHashFunc)mono_metadata_type_hash, (GCompareFunc)mono_metadata_type_equal);
363         image->blob_cache = g_hash_table_new ((GHashFunc)mono_blob_entry_hash, (GCompareFunc)mono_blob_entry_equal);
364         image->gen_params = g_ptr_array_new ();
365         image->remapped_tokens = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_REFLECTION, "dynamic module remapped tokens table");
366
367         /*g_print ("string heap create for image %p (%s)\n", image, module_name);*/
368         string_heap_init (&image->sheap);
369         mono_dynstream_add_data (&image->us, "", 1);
370         mono_dynamic_image_add_to_blob_cached (image, (char*) "", 1, NULL, 0);
371         /* import tables... */
372         mono_dynstream_add_data (&image->code, (char*)entrycode, sizeof (entrycode));
373         image->iat_offset = mono_dynstream_add_zero (&image->code, 8); /* two IAT entries */
374         image->idt_offset = mono_dynstream_add_zero (&image->code, 2 * sizeof (MonoIDT)); /* two IDT entries */
375         image->imp_names_offset = mono_dynstream_add_zero (&image->code, 2); /* flags for name entry */
376         mono_dynstream_add_data (&image->code, "_CorExeMain", 12);
377         mono_dynstream_add_data (&image->code, "mscoree.dll", 12);
378         image->ilt_offset = mono_dynstream_add_zero (&image->code, 8); /* two ILT entries */
379         mono_dynstream_data_align (&image->code);
380
381         image->cli_header_offset = mono_dynstream_add_zero (&image->code, sizeof (MonoCLIHeader));
382
383         for (i=0; i < MONO_TABLE_NUM; ++i) {
384                 image->tables [i].next_idx = 1;
385                 image->tables [i].columns = table_sizes [i];
386         }
387
388         image->image.assembly = (MonoAssembly*)assembly;
389         image->run = assembly->run;
390         image->save = assembly->save;
391         image->pe_kind = 0x1; /* ILOnly */
392         image->machine = 0x14c; /* I386 */
393         
394         MONO_PROFILER_RAISE (image_loaded, (&image->image));
395
396         dynamic_images_lock ();
397
398         if (!dynamic_images)
399                 dynamic_images = g_ptr_array_new ();
400
401         g_ptr_array_add (dynamic_images, image);
402
403         dynamic_images_unlock ();
404
405         return image;
406 }
407 #else /* DISABLE_REFLECTION_EMIT */
408 MonoDynamicImage*
409 mono_dynamic_image_create (MonoDynamicAssembly *assembly, char *assembly_name, char *module_name)
410 {
411         g_assert_not_reached ();
412         return NULL;
413 }
414 #endif /* DISABLE_REFLECTION_EMIT */
415
416 guint32
417 mono_dynamic_image_add_to_blob_cached (MonoDynamicImage *assembly, char *b1, int s1, char *b2, int s2)
418 {
419         MONO_REQ_GC_NEUTRAL_MODE;
420
421         guint32 idx;
422         char *copy;
423         gpointer oldkey, oldval;
424
425         copy = (char *)g_malloc (s1+s2);
426         memcpy (copy, b1, s1);
427         memcpy (copy + s1, b2, s2);
428         if (g_hash_table_lookup_extended (assembly->blob_cache, copy, &oldkey, &oldval)) {
429                 g_free (copy);
430                 idx = GPOINTER_TO_UINT (oldval);
431         } else {
432                 idx = mono_dynstream_add_data (&assembly->blob, b1, s1);
433                 mono_dynstream_add_data (&assembly->blob, b2, s2);
434                 g_hash_table_insert (assembly->blob_cache, copy, GUINT_TO_POINTER (idx));
435         }
436         return idx;
437 }
438
439 void
440 mono_dynimage_alloc_table (MonoDynamicTable *table, guint nrows)
441 {
442         MONO_REQ_GC_NEUTRAL_MODE;
443
444         table->rows = nrows;
445         g_assert (table->columns);
446         if (nrows + 1 >= table->alloc_rows) {
447                 while (nrows + 1 >= table->alloc_rows) {
448                         if (table->alloc_rows == 0)
449                                 table->alloc_rows = 16;
450                         else
451                                 table->alloc_rows *= 2;
452                 }
453
454                 table->values = (guint32 *)g_renew (guint32, table->values, (table->alloc_rows) * table->columns);
455         }
456 }
457
458
459 static void
460 free_blob_cache_entry (gpointer key, gpointer val, gpointer user_data)
461 {
462         g_free (key);
463 }
464
465 static void
466 release_hashtable (MonoGHashTable **hash)
467 {
468         if (*hash) {
469                 mono_g_hash_table_destroy (*hash);
470                 *hash = NULL;
471         }
472 }
473
474 void
475 mono_dynamic_image_release_gc_roots (MonoDynamicImage *image)
476 {
477         release_hashtable (&image->token_fixups);
478         release_hashtable (&image->handleref_managed);
479         release_hashtable (&image->tokens);
480         release_hashtable (&image->remapped_tokens);
481         release_hashtable (&image->generic_def_objects);
482 }
483
484 // Free dynamic image pass one: Free resources but not image itself
485 void
486 mono_dynamic_image_free (MonoDynamicImage *image)
487 {
488         MonoDynamicImage *di = image;
489         GList *list;
490         int i;
491
492         if (di->typespec)
493                 g_hash_table_destroy (di->typespec);
494         if (di->typeref)
495                 g_hash_table_destroy (di->typeref);
496         if (di->handleref)
497                 g_hash_table_destroy (di->handleref);
498         if (di->handleref_managed)
499                 mono_g_hash_table_destroy (di->handleref_managed);
500         if (di->tokens)
501                 mono_g_hash_table_destroy (di->tokens);
502         if (di->remapped_tokens)
503                 mono_g_hash_table_destroy (di->remapped_tokens);
504         if (di->generic_def_objects)
505                 mono_g_hash_table_destroy (di->generic_def_objects);
506         if (di->blob_cache) {
507                 g_hash_table_foreach (di->blob_cache, free_blob_cache_entry, NULL);
508                 g_hash_table_destroy (di->blob_cache);
509         }
510         if (di->standalonesig_cache)
511                 g_hash_table_destroy (di->standalonesig_cache);
512         for (list = di->array_methods; list; list = list->next) {
513                 ArrayMethod *am = (ArrayMethod *)list->data;
514                 mono_sre_array_method_free (am);
515         }
516         g_list_free (di->array_methods);
517         if (di->gen_params) {
518                 for (i = 0; i < di->gen_params->len; i++) {
519                         GenericParamTableEntry *entry = (GenericParamTableEntry *)g_ptr_array_index (di->gen_params, i);
520                         mono_sre_generic_param_table_entry_free (entry);
521                 }
522                 g_ptr_array_free (di->gen_params, TRUE);
523         }
524         if (di->token_fixups)
525                 mono_g_hash_table_destroy (di->token_fixups);
526         if (di->method_to_table_idx)
527                 g_hash_table_destroy (di->method_to_table_idx);
528         if (di->field_to_table_idx)
529                 g_hash_table_destroy (di->field_to_table_idx);
530         if (di->method_aux_hash)
531                 g_hash_table_destroy (di->method_aux_hash);
532         if (di->vararg_aux_hash)
533                 g_hash_table_destroy (di->vararg_aux_hash);
534         g_free (di->strong_name);
535         g_free (di->win32_res);
536         if (di->public_key)
537                 g_free (di->public_key);
538
539         /*g_print ("string heap destroy for image %p\n", di);*/
540         mono_dynamic_stream_reset (&di->sheap);
541         mono_dynamic_stream_reset (&di->code);
542         mono_dynamic_stream_reset (&di->resources);
543         mono_dynamic_stream_reset (&di->us);
544         mono_dynamic_stream_reset (&di->blob);
545         mono_dynamic_stream_reset (&di->tstream);
546         mono_dynamic_stream_reset (&di->guid);
547         for (i = 0; i < MONO_TABLE_NUM; ++i) {
548                 g_free (di->tables [i].values);
549         }
550
551         dynamic_images_lock ();
552
553         if (dynamic_images)
554                 g_ptr_array_remove (dynamic_images, di);
555
556         dynamic_images_unlock ();
557 }
558
559 // Free dynamic image pass two: Free image itself (might never get called in some debug modes)
560 void
561 mono_dynamic_image_free_image (MonoDynamicImage *image)
562 {
563         g_free (image);
564 }