3 * Images created at runtime.
7 * Paolo Molaro (lupus@ximian.com)
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
14 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
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"
31 const unsigned char table_sizes [MONO_TABLE_NUM] = {
41 MONO_INTERFACEIMPL_SIZE,
42 MONO_MEMBERREF_SIZE, /* 0x0A */
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,
53 MONO_PROPERTY_MAP_SIZE,
56 MONO_METHOD_SEMA_SIZE,
58 MONO_MODULEREF_SIZE, /* 0x1A */
64 MONO_ASSEMBLY_SIZE, /* 0x20 */
65 MONO_ASSEMBLY_PROCESSOR_SIZE,
67 MONO_ASSEMBLYREF_SIZE,
68 MONO_ASSEMBLYREFPROC_SIZE,
69 MONO_ASSEMBLYREFOS_SIZE,
73 MONO_NESTED_CLASS_SIZE,
75 MONO_GENERICPARAM_SIZE, /* 0x2A */
77 MONO_GENPARCONSTRAINT_SIZE
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;
86 dynamic_images_lock (void)
88 mono_os_mutex_lock (&dynamic_images_mutex);
92 dynamic_images_unlock (void)
94 mono_os_mutex_unlock (&dynamic_images_mutex);
98 mono_dynamic_images_init (void)
100 mono_os_mutex_init (&dynamic_images_mutex);
103 #ifndef DISABLE_REFLECTION_EMIT
105 string_heap_init (MonoDynamicStream *sh)
107 mono_dynstream_init (sh);
111 #ifndef DISABLE_REFLECTION_EMIT
113 mono_blob_entry_hash (const char* str)
115 MONO_REQ_GC_NEUTRAL_MODE;
119 len = mono_metadata_decode_blob_size (str, &str);
123 for (str += 1; str < end; str++)
124 h = (h << 5) - h + *str;
132 mono_blob_entry_equal (const char *str1, const char *str2) {
133 MONO_REQ_GC_NEUTRAL_MODE;
138 len = mono_metadata_decode_blob_size (str1, &end1);
139 len2 = mono_metadata_decode_blob_size (str2, &end2);
142 return memcmp (end1, end2, len) == 0;
148 * mono_find_dynamic_image_owner:
150 * Find the dynamic image, if any, which a given pointer is located in the memory of.
153 mono_find_dynamic_image_owner (void *ptr)
155 MonoImage *owner = NULL;
158 dynamic_images_lock ();
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))
169 dynamic_images_unlock ();
175 dynamic_image_lock (MonoDynamicImage *image)
178 mono_image_lock ((MonoImage*)image);
183 dynamic_image_unlock (MonoDynamicImage *image)
185 mono_image_unlock ((MonoImage*)image);
188 #ifndef DISABLE_REFLECTION_EMIT
190 * mono_dynamic_image_register_token:
192 * Register the TOKEN->OBJ mapping in the mapping table in ASSEMBLY. This is required for
193 * the Module.ResolveXXXToken () methods to work.
196 mono_dynamic_image_register_token (MonoDynamicImage *assembly, guint32 token, MonoObjectHandle obj, int how_collide)
198 MONO_REQ_GC_UNSAFE_MODE;
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));
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));
211 case MONO_DYN_IMAGE_TOK_REPLACE:
214 g_assert_not_reached ();
217 mono_g_hash_table_insert (assembly->tokens, GUINT_TO_POINTER (token), MONO_HANDLE_RAW (obj));
218 dynamic_image_unlock (assembly);
222 mono_dynamic_image_register_token (MonoDynamicImage *assembly, guint32 token, MonoObjectHandle obj, int how_collide)
228 lookup_dyn_token (MonoDynamicImage *assembly, guint32 token)
230 MONO_REQ_GC_UNSAFE_MODE;
234 dynamic_image_lock (assembly);
235 obj = (MonoObject *)mono_g_hash_table_lookup (assembly->tokens, GUINT_TO_POINTER (token));
236 dynamic_image_unlock (assembly);
241 #ifndef DISABLE_REFLECTION_EMIT
243 mono_dynamic_image_get_registered_token (MonoDynamicImage *dynimage, guint32 token, MonoError *error)
246 return MONO_HANDLE_NEW (MonoObject, lookup_dyn_token (dynimage, token));
248 #else /* DISABLE_REFLECTION_EMIT */
250 mono_dynamic_image_get_registered_token (MonoDynamicImage *dynimage, guint32 token, MonoError *error)
252 g_assert_not_reached ();
259 * mono_dynamic_image_is_valid_token:
261 * Returns TRUE if token is valid in the given image.
265 mono_dynamic_image_is_valid_token (MonoDynamicImage *image, guint32 token)
267 return lookup_dyn_token (image, token) != NULL;
270 #ifndef DISABLE_REFLECTION_EMIT
272 #endif /* DISABLE_REFLECTION_EMIT */
274 #ifndef DISABLE_REFLECTION_EMIT
276 * mono_reflection_lookup_dynamic_token:
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
283 * LOCKING: Take the loader lock
286 mono_reflection_lookup_dynamic_token (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context, MonoError *error)
288 MonoDynamicImage *assembly = (MonoDynamicImage*)image;
294 obj = lookup_dyn_token (assembly, token);
297 g_error ("Could not find required dynamic token 0x%08x", token);
299 mono_error_set_execution_engine (error, "Could not find dynamic token 0x%08x", token);
305 handle_class = &klass;
306 gpointer result = mono_reflection_resolve_object (image, obj, handle_class, context, error);
309 #else /* DISABLE_REFLECTION_EMIT */
311 mono_reflection_lookup_dynamic_token (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context, MonoError *error)
316 #endif /* DISABLE_REFLECTION_EMIT */
318 #ifndef DISABLE_REFLECTION_EMIT
320 mono_dynamic_image_create (MonoDynamicAssembly *assembly, char *assembly_name, char *module_name)
322 static const guchar entrycode [16] = {0xff, 0x25, 0};
323 MonoDynamicImage *image;
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 */
331 version = mono_get_runtime_info ()->runtime_version;
333 image = g_new0 (MonoDynamicImage, 1);
335 MONO_PROFILER_RAISE (image_loading, (&image->image));
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;
347 image->image.references = g_new0 (MonoAssembly*, 1);
348 image->image.references [0] = NULL;
350 mono_image_init (&image->image);
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->tokens = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_REFLECTION, "dynamic module tokens table");
359 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");
360 image->typespec = g_hash_table_new ((GHashFunc)mono_metadata_type_hash, (GCompareFunc)mono_metadata_type_equal);
361 image->typeref = g_hash_table_new ((GHashFunc)mono_metadata_type_hash, (GCompareFunc)mono_metadata_type_equal);
362 image->blob_cache = g_hash_table_new ((GHashFunc)mono_blob_entry_hash, (GCompareFunc)mono_blob_entry_equal);
363 image->gen_params = g_ptr_array_new ();
364 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 /*g_print ("string heap create for image %p (%s)\n", image, module_name);*/
367 string_heap_init (&image->sheap);
368 mono_dynstream_add_data (&image->us, "", 1);
369 mono_dynamic_image_add_to_blob_cached (image, (char*) "", 1, NULL, 0);
370 /* import tables... */
371 mono_dynstream_add_data (&image->code, (char*)entrycode, sizeof (entrycode));
372 image->iat_offset = mono_dynstream_add_zero (&image->code, 8); /* two IAT entries */
373 image->idt_offset = mono_dynstream_add_zero (&image->code, 2 * sizeof (MonoIDT)); /* two IDT entries */
374 image->imp_names_offset = mono_dynstream_add_zero (&image->code, 2); /* flags for name entry */
375 mono_dynstream_add_data (&image->code, "_CorExeMain", 12);
376 mono_dynstream_add_data (&image->code, "mscoree.dll", 12);
377 image->ilt_offset = mono_dynstream_add_zero (&image->code, 8); /* two ILT entries */
378 mono_dynstream_data_align (&image->code);
380 image->cli_header_offset = mono_dynstream_add_zero (&image->code, sizeof (MonoCLIHeader));
382 for (i=0; i < MONO_TABLE_NUM; ++i) {
383 image->tables [i].next_idx = 1;
384 image->tables [i].columns = table_sizes [i];
387 image->image.assembly = (MonoAssembly*)assembly;
388 image->run = assembly->run;
389 image->save = assembly->save;
390 image->pe_kind = 0x1; /* ILOnly */
391 image->machine = 0x14c; /* I386 */
393 MONO_PROFILER_RAISE (image_loaded, (&image->image));
395 dynamic_images_lock ();
398 dynamic_images = g_ptr_array_new ();
400 g_ptr_array_add (dynamic_images, image);
402 dynamic_images_unlock ();
406 #else /* DISABLE_REFLECTION_EMIT */
408 mono_dynamic_image_create (MonoDynamicAssembly *assembly, char *assembly_name, char *module_name)
410 g_assert_not_reached ();
413 #endif /* DISABLE_REFLECTION_EMIT */
416 mono_dynamic_image_add_to_blob_cached (MonoDynamicImage *assembly, char *b1, int s1, char *b2, int s2)
418 MONO_REQ_GC_NEUTRAL_MODE;
422 gpointer oldkey, oldval;
424 copy = (char *)g_malloc (s1+s2);
425 memcpy (copy, b1, s1);
426 memcpy (copy + s1, b2, s2);
427 if (g_hash_table_lookup_extended (assembly->blob_cache, copy, &oldkey, &oldval)) {
429 idx = GPOINTER_TO_UINT (oldval);
431 idx = mono_dynstream_add_data (&assembly->blob, b1, s1);
432 mono_dynstream_add_data (&assembly->blob, b2, s2);
433 g_hash_table_insert (assembly->blob_cache, copy, GUINT_TO_POINTER (idx));
439 mono_dynimage_alloc_table (MonoDynamicTable *table, guint nrows)
441 MONO_REQ_GC_NEUTRAL_MODE;
444 g_assert (table->columns);
445 if (nrows + 1 >= table->alloc_rows) {
446 while (nrows + 1 >= table->alloc_rows) {
447 if (table->alloc_rows == 0)
448 table->alloc_rows = 16;
450 table->alloc_rows *= 2;
453 table->values = (guint32 *)g_renew (guint32, table->values, (table->alloc_rows) * table->columns);
459 free_blob_cache_entry (gpointer key, gpointer val, gpointer user_data)
465 release_hashtable (MonoGHashTable **hash)
468 mono_g_hash_table_destroy (*hash);
474 mono_dynamic_image_release_gc_roots (MonoDynamicImage *image)
476 release_hashtable (&image->token_fixups);
477 release_hashtable (&image->tokens);
478 release_hashtable (&image->remapped_tokens);
479 release_hashtable (&image->generic_def_objects);
482 // Free dynamic image pass one: Free resources but not image itself
484 mono_dynamic_image_free (MonoDynamicImage *image)
486 MonoDynamicImage *di = image;
491 g_hash_table_destroy (di->typespec);
493 g_hash_table_destroy (di->typeref);
495 g_hash_table_destroy (di->handleref);
497 mono_g_hash_table_destroy (di->tokens);
498 if (di->remapped_tokens)
499 mono_g_hash_table_destroy (di->remapped_tokens);
500 if (di->generic_def_objects)
501 mono_g_hash_table_destroy (di->generic_def_objects);
502 if (di->blob_cache) {
503 g_hash_table_foreach (di->blob_cache, free_blob_cache_entry, NULL);
504 g_hash_table_destroy (di->blob_cache);
506 if (di->standalonesig_cache)
507 g_hash_table_destroy (di->standalonesig_cache);
508 for (list = di->array_methods; list; list = list->next) {
509 ArrayMethod *am = (ArrayMethod *)list->data;
510 mono_sre_array_method_free (am);
512 g_list_free (di->array_methods);
513 if (di->gen_params) {
514 for (i = 0; i < di->gen_params->len; i++) {
515 GenericParamTableEntry *entry = (GenericParamTableEntry *)g_ptr_array_index (di->gen_params, i);
516 mono_sre_generic_param_table_entry_free (entry);
518 g_ptr_array_free (di->gen_params, TRUE);
520 if (di->token_fixups)
521 mono_g_hash_table_destroy (di->token_fixups);
522 if (di->method_to_table_idx)
523 g_hash_table_destroy (di->method_to_table_idx);
524 if (di->field_to_table_idx)
525 g_hash_table_destroy (di->field_to_table_idx);
526 if (di->method_aux_hash)
527 g_hash_table_destroy (di->method_aux_hash);
528 if (di->vararg_aux_hash)
529 g_hash_table_destroy (di->vararg_aux_hash);
530 g_free (di->strong_name);
531 g_free (di->win32_res);
533 g_free (di->public_key);
535 /*g_print ("string heap destroy for image %p\n", di);*/
536 mono_dynamic_stream_reset (&di->sheap);
537 mono_dynamic_stream_reset (&di->code);
538 mono_dynamic_stream_reset (&di->resources);
539 mono_dynamic_stream_reset (&di->us);
540 mono_dynamic_stream_reset (&di->blob);
541 mono_dynamic_stream_reset (&di->tstream);
542 mono_dynamic_stream_reset (&di->guid);
543 for (i = 0; i < MONO_TABLE_NUM; ++i) {
544 g_free (di->tables [i].values);
547 dynamic_images_lock ();
550 g_ptr_array_remove (dynamic_images, di);
552 dynamic_images_unlock ();
555 // Free dynamic image pass two: Free image itself (might never get called in some debug modes)
557 mono_dynamic_image_free_image (MonoDynamicImage *image)