Merge pull request #3936 from kumpera/monoclass_reorg2
[mono-project.git] / mono / metadata / dynamic-image.c
blob9906f43b31838ec448675aeab80c281ee262d8c1
1 /*
2 * dynamic-image.c: Images created at runtime.
3 *
4 *
5 * Author:
6 * Paolo Molaro (lupus@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
10 * Copyright 2011 Rodrigo Kumpera
11 * Copyright 2016 Microsoft
13 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
16 #include <config.h>
17 #include <glib.h>
18 #include "mono/metadata/object.h"
19 #include "mono/metadata/dynamic-image-internals.h"
20 #include "mono/metadata/dynamic-stream-internals.h"
21 #include "mono/metadata/gc-internals.h"
22 #include "mono/metadata/metadata-internals.h"
23 #include "mono/metadata/profiler-private.h"
24 #include "mono/metadata/reflection-internals.h"
25 #include "mono/metadata/sre-internals.h"
26 #include "mono/utils/checked-build.h"
27 #include "mono/utils/mono-error-internals.h"
28 #include "mono/utils/mono-os-mutex.h"
30 const unsigned char table_sizes [MONO_TABLE_NUM] = {
31 MONO_MODULE_SIZE,
32 MONO_TYPEREF_SIZE,
33 MONO_TYPEDEF_SIZE,
35 MONO_FIELD_SIZE,
37 MONO_METHOD_SIZE,
39 MONO_PARAM_SIZE,
40 MONO_INTERFACEIMPL_SIZE,
41 MONO_MEMBERREF_SIZE, /* 0x0A */
42 MONO_CONSTANT_SIZE,
43 MONO_CUSTOM_ATTR_SIZE,
44 MONO_FIELD_MARSHAL_SIZE,
45 MONO_DECL_SECURITY_SIZE,
46 MONO_CLASS_LAYOUT_SIZE,
47 MONO_FIELD_LAYOUT_SIZE, /* 0x10 */
48 MONO_STAND_ALONE_SIGNATURE_SIZE,
49 MONO_EVENT_MAP_SIZE,
51 MONO_EVENT_SIZE,
52 MONO_PROPERTY_MAP_SIZE,
54 MONO_PROPERTY_SIZE,
55 MONO_METHOD_SEMA_SIZE,
56 MONO_METHODIMPL_SIZE,
57 MONO_MODULEREF_SIZE, /* 0x1A */
58 MONO_TYPESPEC_SIZE,
59 MONO_IMPLMAP_SIZE,
60 MONO_FIELD_RVA_SIZE,
63 MONO_ASSEMBLY_SIZE, /* 0x20 */
64 MONO_ASSEMBLY_PROCESSOR_SIZE,
65 MONO_ASSEMBLYOS_SIZE,
66 MONO_ASSEMBLYREF_SIZE,
67 MONO_ASSEMBLYREFPROC_SIZE,
68 MONO_ASSEMBLYREFOS_SIZE,
69 MONO_FILE_SIZE,
70 MONO_EXP_TYPE_SIZE,
71 MONO_MANIFEST_SIZE,
72 MONO_NESTED_CLASS_SIZE,
74 MONO_GENERICPARAM_SIZE, /* 0x2A */
75 MONO_METHODSPEC_SIZE,
76 MONO_GENPARCONSTRAINT_SIZE
80 // The dynamic images list is only needed to support the mempool reference tracking feature in checked-build.
81 static GPtrArray *dynamic_images;
82 static mono_mutex_t dynamic_images_mutex;
84 static inline void
85 dynamic_images_lock (void)
87 mono_os_mutex_lock (&dynamic_images_mutex);
90 static inline void
91 dynamic_images_unlock (void)
93 mono_os_mutex_unlock (&dynamic_images_mutex);
96 void
97 mono_dynamic_images_init (void)
99 mono_os_mutex_init (&dynamic_images_mutex);
102 #ifndef DISABLE_REFLECTION_EMIT
103 static void
104 string_heap_init (MonoDynamicStream *sh)
106 mono_dynstream_init (sh);
108 #endif
110 #ifndef DISABLE_REFLECTION_EMIT
111 static int
112 mono_blob_entry_hash (const char* str)
114 MONO_REQ_GC_NEUTRAL_MODE;
116 guint len, h;
117 const char *end;
118 len = mono_metadata_decode_blob_size (str, &str);
119 if (len > 0) {
120 end = str + len;
121 h = *str;
122 for (str += 1; str < end; str++)
123 h = (h << 5) - h + *str;
124 return h;
125 } else {
126 return 0;
130 static gboolean
131 mono_blob_entry_equal (const char *str1, const char *str2) {
132 MONO_REQ_GC_NEUTRAL_MODE;
134 int len, len2;
135 const char *end1;
136 const char *end2;
137 len = mono_metadata_decode_blob_size (str1, &end1);
138 len2 = mono_metadata_decode_blob_size (str2, &end2);
139 if (len != len2)
140 return 0;
141 return memcmp (end1, end2, len) == 0;
143 #endif
147 * mono_find_dynamic_image_owner:
149 * Find the dynamic image, if any, which a given pointer is located in the memory of.
151 MonoImage *
152 mono_find_dynamic_image_owner (void *ptr)
154 MonoImage *owner = NULL;
155 int i;
157 dynamic_images_lock ();
159 if (dynamic_images)
161 for (i = 0; !owner && i < dynamic_images->len; ++i) {
162 MonoImage *image = (MonoImage *)g_ptr_array_index (dynamic_images, i);
163 if (mono_mempool_contains_addr (image->mempool, ptr))
164 owner = image;
168 dynamic_images_unlock ();
170 return owner;
173 static inline void
174 dynamic_image_lock (MonoDynamicImage *image)
176 MONO_ENTER_GC_SAFE;
177 mono_image_lock ((MonoImage*)image);
178 MONO_EXIT_GC_SAFE;
181 static inline void
182 dynamic_image_unlock (MonoDynamicImage *image)
184 mono_image_unlock ((MonoImage*)image);
187 void
188 mono_dynamic_image_register_token (MonoDynamicImage *assembly, guint32 token, MonoObject *obj)
190 MONO_REQ_GC_UNSAFE_MODE;
192 dynamic_image_lock (assembly);
193 mono_g_hash_table_insert (assembly->tokens, GUINT_TO_POINTER (token), obj);
194 dynamic_image_unlock (assembly);
197 static MonoObject*
198 lookup_dyn_token (MonoDynamicImage *assembly, guint32 token)
200 MONO_REQ_GC_UNSAFE_MODE;
202 MonoObject *obj;
204 dynamic_image_lock (assembly);
205 obj = (MonoObject *)mono_g_hash_table_lookup (assembly->tokens, GUINT_TO_POINTER (token));
206 dynamic_image_unlock (assembly);
208 return obj;
213 * mono_dynamic_image_is_valid_token:
215 * Returns TRUE if token is valid in the given image.
218 gboolean
219 mono_dynamic_image_is_valid_token (MonoDynamicImage *image, guint32 token)
221 return lookup_dyn_token (image, token) != NULL;
224 #ifndef DISABLE_REFLECTION_EMIT
226 #endif /* DISABLE_REFLECTION_EMIT */
228 #ifndef DISABLE_REFLECTION_EMIT
230 * mono_reflection_lookup_dynamic_token:
232 * Finish the Builder object pointed to by TOKEN and return the corresponding
233 * runtime structure. If HANDLE_CLASS is not NULL, it is set to the class required by
234 * mono_ldtoken. If valid_token is TRUE, assert if it is not found in the token->object
235 * mapping table.
237 * LOCKING: Take the loader lock
239 gpointer
240 mono_reflection_lookup_dynamic_token (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context, MonoError *error)
242 MonoDynamicImage *assembly = (MonoDynamicImage*)image;
243 MonoObject *obj;
244 MonoClass *klass;
246 mono_error_init (error);
248 obj = lookup_dyn_token (assembly, token);
249 if (!obj) {
250 if (valid_token)
251 g_error ("Could not find required dynamic token 0x%08x", token);
252 else {
253 mono_error_set_execution_engine (error, "Could not find dynamic token 0x%08x", token);
254 return NULL;
258 if (!handle_class)
259 handle_class = &klass;
260 gpointer result = mono_reflection_resolve_object (image, obj, handle_class, context, error);
261 return result;
265 * mono_image_register_token:
267 * Register the TOKEN->OBJ mapping in the mapping table in ASSEMBLY. This is required for
268 * the Module.ResolveXXXToken () methods to work.
270 void
271 mono_image_register_token (MonoDynamicImage *assembly, guint32 token, MonoObject *obj)
273 MonoObject *prev;
275 dynamic_image_lock (assembly);
276 prev = (MonoObject *)mono_g_hash_table_lookup (assembly->tokens, GUINT_TO_POINTER (token));
277 if (prev) {
278 /* There could be multiple MethodInfo objects with the same token */
279 //g_assert (prev == obj);
280 } else {
281 mono_g_hash_table_insert (assembly->tokens, GUINT_TO_POINTER (token), obj);
283 dynamic_image_unlock (assembly);
286 #else /* DISABLE_REFLECTION_EMIT */
288 gpointer
289 mono_reflection_lookup_dynamic_token (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context, MonoError *error)
291 mono_error_init (error);
292 return NULL;
295 void
296 mono_image_register_token (MonoDynamicImage *assembly, guint32 token, MonoObject *obj)
300 #endif /* DISABLE_REFLECTION_EMIT */
302 #ifndef DISABLE_REFLECTION_EMIT
303 MonoDynamicImage*
304 mono_dynamic_image_create (MonoDynamicAssembly *assembly, char *assembly_name, char *module_name)
306 static const guchar entrycode [16] = {0xff, 0x25, 0};
307 MonoDynamicImage *image;
308 int i;
310 const char *version;
312 if (!strcmp (mono_get_runtime_info ()->framework_version, "2.1"))
313 version = "v2.0.50727"; /* HACK: SL 2 enforces the .net 2 metadata version */
314 else
315 version = mono_get_runtime_info ()->runtime_version;
317 #if HAVE_BOEHM_GC
318 /* The MonoGHashTable's need GC tracking */
319 image = (MonoDynamicImage *)GC_MALLOC (sizeof (MonoDynamicImage));
320 #else
321 image = g_new0 (MonoDynamicImage, 1);
322 #endif
324 mono_profiler_module_event (&image->image, MONO_PROFILE_START_LOAD);
326 /*g_print ("created image %p\n", image);*/
327 /* keep in sync with image.c */
328 image->image.name = assembly_name;
329 image->image.assembly_name = image->image.name; /* they may be different */
330 image->image.module_name = module_name;
331 image->image.version = g_strdup (version);
332 image->image.md_version_major = 1;
333 image->image.md_version_minor = 1;
334 image->image.dynamic = TRUE;
336 image->image.references = g_new0 (MonoAssembly*, 1);
337 image->image.references [0] = NULL;
339 mono_image_init (&image->image);
341 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");
342 image->method_to_table_idx = g_hash_table_new (NULL, NULL);
343 image->field_to_table_idx = g_hash_table_new (NULL, NULL);
344 image->method_aux_hash = g_hash_table_new (NULL, NULL);
345 image->vararg_aux_hash = g_hash_table_new (NULL, NULL);
346 image->handleref = g_hash_table_new (NULL, NULL);
347 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");
348 image->tokens = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_REFLECTION, "dynamic module tokens table");
349 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");
350 image->typespec = g_hash_table_new ((GHashFunc)mono_metadata_type_hash, (GCompareFunc)mono_metadata_type_equal);
351 image->typeref = g_hash_table_new ((GHashFunc)mono_metadata_type_hash, (GCompareFunc)mono_metadata_type_equal);
352 image->blob_cache = g_hash_table_new ((GHashFunc)mono_blob_entry_hash, (GCompareFunc)mono_blob_entry_equal);
353 image->gen_params = g_ptr_array_new ();
354 image->remapped_tokens = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_REFLECTION, "dynamic module remapped tokens table");
356 /*g_print ("string heap create for image %p (%s)\n", image, module_name);*/
357 string_heap_init (&image->sheap);
358 mono_dynstream_add_data (&image->us, "", 1);
359 mono_dynamic_image_add_to_blob_cached (image, (char*) "", 1, NULL, 0);
360 /* import tables... */
361 mono_dynstream_add_data (&image->code, (char*)entrycode, sizeof (entrycode));
362 image->iat_offset = mono_dynstream_add_zero (&image->code, 8); /* two IAT entries */
363 image->idt_offset = mono_dynstream_add_zero (&image->code, 2 * sizeof (MonoIDT)); /* two IDT entries */
364 image->imp_names_offset = mono_dynstream_add_zero (&image->code, 2); /* flags for name entry */
365 mono_dynstream_add_data (&image->code, "_CorExeMain", 12);
366 mono_dynstream_add_data (&image->code, "mscoree.dll", 12);
367 image->ilt_offset = mono_dynstream_add_zero (&image->code, 8); /* two ILT entries */
368 mono_dynstream_data_align (&image->code);
370 image->cli_header_offset = mono_dynstream_add_zero (&image->code, sizeof (MonoCLIHeader));
372 for (i=0; i < MONO_TABLE_NUM; ++i) {
373 image->tables [i].next_idx = 1;
374 image->tables [i].columns = table_sizes [i];
377 image->image.assembly = (MonoAssembly*)assembly;
378 image->run = assembly->run;
379 image->save = assembly->save;
380 image->pe_kind = 0x1; /* ILOnly */
381 image->machine = 0x14c; /* I386 */
383 mono_profiler_module_loaded (&image->image, MONO_PROFILE_OK);
385 dynamic_images_lock ();
387 if (!dynamic_images)
388 dynamic_images = g_ptr_array_new ();
390 g_ptr_array_add (dynamic_images, image);
392 dynamic_images_unlock ();
394 return image;
396 #else /* DISABLE_REFLECTION_EMIT */
397 MonoDynamicImage*
398 mono_dynamic_image_create (MonoDynamicAssembly *assembly, char *assembly_name, char *module_name)
400 g_assert_not_reached ();
401 return NULL;
403 #endif /* DISABLE_REFLECTION_EMIT */
405 guint32
406 mono_dynamic_image_add_to_blob_cached (MonoDynamicImage *assembly, char *b1, int s1, char *b2, int s2)
408 MONO_REQ_GC_NEUTRAL_MODE;
410 guint32 idx;
411 char *copy;
412 gpointer oldkey, oldval;
414 copy = (char *)g_malloc (s1+s2);
415 memcpy (copy, b1, s1);
416 memcpy (copy + s1, b2, s2);
417 if (g_hash_table_lookup_extended (assembly->blob_cache, copy, &oldkey, &oldval)) {
418 g_free (copy);
419 idx = GPOINTER_TO_UINT (oldval);
420 } else {
421 idx = mono_dynstream_add_data (&assembly->blob, b1, s1);
422 mono_dynstream_add_data (&assembly->blob, b2, s2);
423 g_hash_table_insert (assembly->blob_cache, copy, GUINT_TO_POINTER (idx));
425 return idx;
428 void
429 mono_dynimage_alloc_table (MonoDynamicTable *table, guint nrows)
431 MONO_REQ_GC_NEUTRAL_MODE;
433 table->rows = nrows;
434 g_assert (table->columns);
435 if (nrows + 1 >= table->alloc_rows) {
436 while (nrows + 1 >= table->alloc_rows) {
437 if (table->alloc_rows == 0)
438 table->alloc_rows = 16;
439 else
440 table->alloc_rows *= 2;
443 table->values = (guint32 *)g_renew (guint32, table->values, (table->alloc_rows) * table->columns);
448 static void
449 free_blob_cache_entry (gpointer key, gpointer val, gpointer user_data)
451 g_free (key);
454 static void
455 release_hashtable (MonoGHashTable **hash)
457 if (*hash) {
458 mono_g_hash_table_destroy (*hash);
459 *hash = NULL;
463 void
464 mono_dynamic_image_release_gc_roots (MonoDynamicImage *image)
466 release_hashtable (&image->token_fixups);
467 release_hashtable (&image->handleref_managed);
468 release_hashtable (&image->tokens);
469 release_hashtable (&image->remapped_tokens);
470 release_hashtable (&image->generic_def_objects);
473 // Free dynamic image pass one: Free resources but not image itself
474 void
475 mono_dynamic_image_free (MonoDynamicImage *image)
477 MonoDynamicImage *di = image;
478 GList *list;
479 int i;
481 if (di->typespec)
482 g_hash_table_destroy (di->typespec);
483 if (di->typeref)
484 g_hash_table_destroy (di->typeref);
485 if (di->handleref)
486 g_hash_table_destroy (di->handleref);
487 if (di->handleref_managed)
488 mono_g_hash_table_destroy (di->handleref_managed);
489 if (di->tokens)
490 mono_g_hash_table_destroy (di->tokens);
491 if (di->remapped_tokens)
492 mono_g_hash_table_destroy (di->remapped_tokens);
493 if (di->generic_def_objects)
494 mono_g_hash_table_destroy (di->generic_def_objects);
495 if (di->blob_cache) {
496 g_hash_table_foreach (di->blob_cache, free_blob_cache_entry, NULL);
497 g_hash_table_destroy (di->blob_cache);
499 if (di->standalonesig_cache)
500 g_hash_table_destroy (di->standalonesig_cache);
501 for (list = di->array_methods; list; list = list->next) {
502 ArrayMethod *am = (ArrayMethod *)list->data;
503 mono_sre_array_method_free (am);
505 g_list_free (di->array_methods);
506 if (di->gen_params) {
507 for (i = 0; i < di->gen_params->len; i++) {
508 GenericParamTableEntry *entry = (GenericParamTableEntry *)g_ptr_array_index (di->gen_params, i);
509 mono_sre_generic_param_table_entry_free (entry);
511 g_ptr_array_free (di->gen_params, TRUE);
513 if (di->token_fixups)
514 mono_g_hash_table_destroy (di->token_fixups);
515 if (di->method_to_table_idx)
516 g_hash_table_destroy (di->method_to_table_idx);
517 if (di->field_to_table_idx)
518 g_hash_table_destroy (di->field_to_table_idx);
519 if (di->method_aux_hash)
520 g_hash_table_destroy (di->method_aux_hash);
521 if (di->vararg_aux_hash)
522 g_hash_table_destroy (di->vararg_aux_hash);
523 g_free (di->strong_name);
524 g_free (di->win32_res);
525 if (di->public_key)
526 g_free (di->public_key);
528 /*g_print ("string heap destroy for image %p\n", di);*/
529 mono_dynamic_stream_reset (&di->sheap);
530 mono_dynamic_stream_reset (&di->code);
531 mono_dynamic_stream_reset (&di->resources);
532 mono_dynamic_stream_reset (&di->us);
533 mono_dynamic_stream_reset (&di->blob);
534 mono_dynamic_stream_reset (&di->tstream);
535 mono_dynamic_stream_reset (&di->guid);
536 for (i = 0; i < MONO_TABLE_NUM; ++i) {
537 g_free (di->tables [i].values);
540 dynamic_images_lock ();
542 if (dynamic_images)
543 g_ptr_array_remove (dynamic_images, di);
545 dynamic_images_unlock ();
548 // Free dynamic image pass two: Free image itself (might never get called in some debug modes)
549 void
550 mono_dynamic_image_free_image (MonoDynamicImage *image)
552 /* See create_dynamic_mono_image () */
553 #if HAVE_BOEHM_GC
554 /* Allocated using GC_MALLOC */
555 #else
556 g_free (image);
557 #endif