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 // The dynamic images list is only needed to support the mempool reference tracking feature in checked-build.
32 static GPtrArray
*dynamic_images
;
33 static mono_mutex_t dynamic_images_mutex
;
36 dynamic_images_lock (void)
38 mono_os_mutex_lock (&dynamic_images_mutex
);
42 dynamic_images_unlock (void)
44 mono_os_mutex_unlock (&dynamic_images_mutex
);
48 mono_dynamic_images_init (void)
50 mono_os_mutex_init (&dynamic_images_mutex
);
53 #ifndef DISABLE_REFLECTION_EMIT
55 string_heap_init (MonoDynamicStream
*sh
)
57 mono_dynstream_init (sh
);
61 #ifndef DISABLE_REFLECTION_EMIT
63 mono_blob_entry_hash (const char* str
)
65 MONO_REQ_GC_NEUTRAL_MODE
;
69 len
= mono_metadata_decode_blob_size (str
, &str
);
73 for (str
+= 1; str
< end
; str
++)
74 h
= (h
<< 5) - h
+ *str
;
82 mono_blob_entry_equal (const char *str1
, const char *str2
) {
83 MONO_REQ_GC_NEUTRAL_MODE
;
88 len
= mono_metadata_decode_blob_size (str1
, &end1
);
89 len2
= mono_metadata_decode_blob_size (str2
, &end2
);
92 return memcmp (end1
, end2
, len
) == 0;
98 * mono_find_dynamic_image_owner:
100 * Find the dynamic image, if any, which a given pointer is located in the memory of.
103 mono_find_dynamic_image_owner (void *ptr
)
105 MonoImage
*owner
= NULL
;
108 dynamic_images_lock ();
112 for (i
= 0; !owner
&& i
< dynamic_images
->len
; ++i
) {
113 MonoImage
*image
= (MonoImage
*)g_ptr_array_index (dynamic_images
, i
);
114 if (mono_mempool_contains_addr (image
->mempool
, ptr
))
119 dynamic_images_unlock ();
125 dynamic_image_lock (MonoDynamicImage
*image
)
128 mono_image_lock ((MonoImage
*)image
);
133 dynamic_image_unlock (MonoDynamicImage
*image
)
135 mono_image_unlock ((MonoImage
*)image
);
138 #ifndef DISABLE_REFLECTION_EMIT
140 * mono_dynamic_image_register_token:
142 * Register the TOKEN->OBJ mapping in the mapping table in ASSEMBLY. This is required for
143 * the Module.ResolveXXXToken () methods to work.
146 mono_dynamic_image_register_token (MonoDynamicImage
*assembly
, guint32 token
, MonoObjectHandle obj
, int how_collide
)
148 MONO_REQ_GC_UNSAFE_MODE
;
150 g_assert (!MONO_HANDLE_IS_NULL (obj
));
151 g_assert (strcmp (m_class_get_name (mono_handle_class (obj
)), "EnumBuilder"));
152 dynamic_image_lock (assembly
);
153 MonoObject
*prev
= (MonoObject
*)mono_g_hash_table_lookup (assembly
->tokens
, GUINT_TO_POINTER (token
));
155 switch (how_collide
) {
156 case MONO_DYN_IMAGE_TOK_NEW
:
157 g_warning ("%s: Unexpected previous object when called with MONO_DYN_IMAGE_TOK_NEW", __func__
);
159 case MONO_DYN_IMAGE_TOK_SAME_OK
:
160 if (prev
!= MONO_HANDLE_RAW (obj
)) {
161 g_warning ("%s: condition `prev == MONO_HANDLE_RAW (obj)' not met", __func__
);
164 case MONO_DYN_IMAGE_TOK_REPLACE
:
167 g_assert_not_reached ();
170 mono_g_hash_table_insert (assembly
->tokens
, GUINT_TO_POINTER (token
), MONO_HANDLE_RAW (obj
));
171 dynamic_image_unlock (assembly
);
175 mono_dynamic_image_register_token (MonoDynamicImage
*assembly
, guint32 token
, MonoObjectHandle obj
, int how_collide
)
181 lookup_dyn_token (MonoDynamicImage
*assembly
, guint32 token
, MonoObjectHandle
*object_handle
)
183 MONO_REQ_GC_UNSAFE_MODE
;
187 dynamic_image_lock (assembly
);
188 obj
= (MonoObject
*)mono_g_hash_table_lookup (assembly
->tokens
, GUINT_TO_POINTER (token
));
189 dynamic_image_unlock (assembly
);
192 *object_handle
= MONO_HANDLE_NEW (MonoObject
, obj
);
197 #ifndef DISABLE_REFLECTION_EMIT
199 mono_dynamic_image_get_registered_token (MonoDynamicImage
*dynimage
, guint32 token
, MonoError
*error
)
201 MonoObjectHandle obj
;
202 lookup_dyn_token (dynimage
, token
, &obj
);
205 #else /* DISABLE_REFLECTION_EMIT */
207 mono_dynamic_image_get_registered_token (MonoDynamicImage
*dynimage
, guint32 token
, MonoError
*error
)
209 g_assert_not_reached ();
216 * mono_dynamic_image_is_valid_token:
218 * Returns TRUE if token is valid in the given image.
222 mono_dynamic_image_is_valid_token (MonoDynamicImage
*image
, guint32 token
)
224 return lookup_dyn_token (image
, token
, NULL
);
227 #ifndef DISABLE_REFLECTION_EMIT
229 #endif /* DISABLE_REFLECTION_EMIT */
231 #ifndef DISABLE_REFLECTION_EMIT
233 * mono_reflection_lookup_dynamic_token:
235 * Finish the Builder object pointed to by TOKEN and return the corresponding
236 * runtime structure. If HANDLE_CLASS is not NULL, it is set to the class required by
237 * mono_ldtoken. If valid_token is TRUE, assert if it is not found in the token->object
240 * LOCKING: Take the loader lock
243 mono_reflection_lookup_dynamic_token (MonoImage
*image
, guint32 token
, gboolean valid_token
, MonoClass
**handle_class
, MonoGenericContext
*context
, MonoError
*error
)
245 HANDLE_FUNCTION_ENTER ();
247 MonoDynamicImage
*assembly
= (MonoDynamicImage
*)image
;
248 MonoObjectHandle obj
;
253 lookup_dyn_token (assembly
, token
, &obj
);
254 if (MONO_HANDLE_IS_NULL (obj
)) {
256 g_error ("Could not find required dynamic token 0x%08x", token
);
258 mono_error_set_execution_engine (error
, "Could not find dynamic token 0x%08x", token
);
264 handle_class
= &klass
;
265 gpointer result
= mono_reflection_resolve_object_handle (image
, obj
, handle_class
, context
, error
);
266 HANDLE_FUNCTION_RETURN_VAL (result
);
268 #else /* DISABLE_REFLECTION_EMIT */
270 mono_reflection_lookup_dynamic_token (MonoImage
*image
, guint32 token
, gboolean valid_token
, MonoClass
**handle_class
, MonoGenericContext
*context
, MonoError
*error
)
275 #endif /* DISABLE_REFLECTION_EMIT */
277 #ifndef DISABLE_REFLECTION_EMIT
279 static const unsigned char table_sizes
[MONO_TABLE_NUM
] = {
289 MONO_INTERFACEIMPL_SIZE
,
290 MONO_MEMBERREF_SIZE
, /* 0x0A */
292 MONO_CUSTOM_ATTR_SIZE
,
293 MONO_FIELD_MARSHAL_SIZE
,
294 MONO_DECL_SECURITY_SIZE
,
295 MONO_CLASS_LAYOUT_SIZE
,
296 MONO_FIELD_LAYOUT_SIZE
, /* 0x10 */
297 MONO_STAND_ALONE_SIGNATURE_SIZE
,
301 MONO_PROPERTY_MAP_SIZE
,
304 MONO_METHOD_SEMA_SIZE
,
305 MONO_METHODIMPL_SIZE
,
306 MONO_MODULEREF_SIZE
, /* 0x1A */
312 MONO_ASSEMBLY_SIZE
, /* 0x20 */
313 MONO_ASSEMBLY_PROCESSOR_SIZE
,
314 MONO_ASSEMBLYOS_SIZE
,
315 MONO_ASSEMBLYREF_SIZE
,
316 MONO_ASSEMBLYREFPROC_SIZE
,
317 MONO_ASSEMBLYREFOS_SIZE
,
321 MONO_NESTED_CLASS_SIZE
,
323 MONO_GENERICPARAM_SIZE
, /* 0x2A */
324 MONO_METHODSPEC_SIZE
,
325 MONO_GENPARCONSTRAINT_SIZE
329 mono_dynamic_image_create (MonoDynamicAssembly
*assembly
, char *assembly_name
, char *module_name
)
331 static const guchar entrycode
[16] = {0xff, 0x25, 0};
332 MonoDynamicImage
*image
;
337 if (!strcmp (mono_get_runtime_info ()->framework_version
, "2.1"))
338 version
= "v2.0.50727"; /* HACK: SL 2 enforces the .net 2 metadata version */
340 version
= mono_get_runtime_info ()->runtime_version
;
342 image
= g_new0 (MonoDynamicImage
, 1);
344 MONO_PROFILER_RAISE (image_loading
, (&image
->image
));
346 /*g_print ("created image %p\n", image);*/
347 /* keep in sync with image.c */
348 image
->image
.name
= assembly_name
;
349 image
->image
.assembly_name
= image
->image
.name
; /* they may be different */
350 image
->image
.module_name
= module_name
;
351 image
->image
.version
= g_strdup (version
);
352 image
->image
.md_version_major
= 1;
353 image
->image
.md_version_minor
= 1;
354 image
->image
.dynamic
= TRUE
;
356 image
->image
.references
= g_new0 (MonoAssembly
*, 1);
357 image
->image
.references
[0] = NULL
;
359 mono_image_init (&image
->image
);
361 image
->token_fixups
= mono_g_hash_table_new_type ((GHashFunc
)mono_object_hash_internal
, NULL
, MONO_HASH_KEY_GC
, MONO_ROOT_SOURCE_REFLECTION
, NULL
, "Reflection Dynamic Image Token Fixup Table");
362 image
->method_to_table_idx
= g_hash_table_new (NULL
, NULL
);
363 image
->field_to_table_idx
= g_hash_table_new (NULL
, NULL
);
364 image
->method_aux_hash
= g_hash_table_new (NULL
, NULL
);
365 image
->vararg_aux_hash
= g_hash_table_new (NULL
, NULL
);
366 image
->handleref
= g_hash_table_new (NULL
, NULL
);
367 image
->tokens
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_VALUE_GC
, MONO_ROOT_SOURCE_REFLECTION
, NULL
, "Reflection Dynamic Image Token Table");
368 image
->generic_def_objects
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_VALUE_GC
, MONO_ROOT_SOURCE_REFLECTION
, NULL
, "Reflection Dynamic Image Generic Definition Table");
369 image
->typespec
= g_hash_table_new ((GHashFunc
)mono_metadata_type_hash
, (GCompareFunc
)mono_metadata_type_equal
);
370 image
->typeref
= g_hash_table_new ((GHashFunc
)mono_metadata_type_hash
, (GCompareFunc
)mono_metadata_type_equal
);
371 image
->blob_cache
= g_hash_table_new ((GHashFunc
)mono_blob_entry_hash
, (GCompareFunc
)mono_blob_entry_equal
);
372 image
->gen_params
= g_ptr_array_new ();
373 image
->remapped_tokens
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_VALUE_GC
, MONO_ROOT_SOURCE_REFLECTION
, NULL
, "Reflection Dynamic Image Remapped Token Table");
375 /*g_print ("string heap create for image %p (%s)\n", image, module_name);*/
376 string_heap_init (&image
->sheap
);
377 mono_dynstream_add_data (&image
->us
, "", 1);
378 mono_dynamic_image_add_to_blob_cached (image
, "", 1, NULL
, 0);
379 /* import tables... */
380 mono_dynstream_add_data (&image
->code
, entrycode
, sizeof (entrycode
));
381 image
->iat_offset
= mono_dynstream_add_zero (&image
->code
, 8); /* two IAT entries */
382 image
->idt_offset
= mono_dynstream_add_zero (&image
->code
, 2 * sizeof (MonoIDT
)); /* two IDT entries */
383 image
->imp_names_offset
= mono_dynstream_add_zero (&image
->code
, 2); /* flags for name entry */
384 mono_dynstream_add_data (&image
->code
, "_CorExeMain", 12);
385 mono_dynstream_add_data (&image
->code
, "mscoree.dll", 12);
386 image
->ilt_offset
= mono_dynstream_add_zero (&image
->code
, 8); /* two ILT entries */
387 mono_dynstream_data_align (&image
->code
);
389 image
->cli_header_offset
= mono_dynstream_add_zero (&image
->code
, sizeof (MonoCLIHeader
));
391 for (i
=0; i
< MONO_TABLE_NUM
; ++i
) {
392 image
->tables
[i
].next_idx
= 1;
393 image
->tables
[i
].columns
= table_sizes
[i
];
396 image
->image
.assembly
= (MonoAssembly
*)assembly
;
397 image
->run
= assembly
->run
;
398 image
->save
= assembly
->save
;
399 image
->pe_kind
= 0x1; /* ILOnly */
400 image
->machine
= 0x14c; /* I386 */
402 MONO_PROFILER_RAISE (image_loaded
, (&image
->image
));
404 dynamic_images_lock ();
407 dynamic_images
= g_ptr_array_new ();
409 g_ptr_array_add (dynamic_images
, image
);
411 dynamic_images_unlock ();
415 #else /* DISABLE_REFLECTION_EMIT */
417 mono_dynamic_image_create (MonoDynamicAssembly
*assembly
, char *assembly_name
, char *module_name
)
419 g_assert_not_reached ();
422 #endif /* DISABLE_REFLECTION_EMIT */
425 mono_dynamic_image_add_to_blob_cached (MonoDynamicImage
*assembly
, gconstpointer b1
, int s1
, gconstpointer b2
, int s2
)
427 MONO_REQ_GC_NEUTRAL_MODE
;
431 gpointer oldkey
, oldval
;
433 copy
= (char *)g_malloc (s1
+s2
);
434 memcpy (copy
, b1
, s1
);
435 memcpy (copy
+ s1
, b2
, s2
);
436 if (g_hash_table_lookup_extended (assembly
->blob_cache
, copy
, &oldkey
, &oldval
)) {
438 idx
= GPOINTER_TO_UINT (oldval
);
440 idx
= mono_dynstream_add_data (&assembly
->blob
, b1
, s1
);
441 mono_dynstream_add_data (&assembly
->blob
, b2
, s2
);
442 g_hash_table_insert (assembly
->blob_cache
, copy
, GUINT_TO_POINTER (idx
));
448 mono_dynimage_alloc_table (MonoDynamicTable
*table
, guint nrows
)
450 MONO_REQ_GC_NEUTRAL_MODE
;
453 g_assert (table
->columns
);
454 if (nrows
+ 1 >= table
->alloc_rows
) {
455 while (nrows
+ 1 >= table
->alloc_rows
) {
456 if (table
->alloc_rows
== 0)
457 table
->alloc_rows
= 16;
459 table
->alloc_rows
*= 2;
462 table
->values
= (guint32
*)g_renew (guint32
, table
->values
, (table
->alloc_rows
) * table
->columns
);
468 free_blob_cache_entry (gpointer key
, gpointer val
, gpointer user_data
)
474 release_hashtable (MonoGHashTable
**hash
)
477 mono_g_hash_table_destroy (*hash
);
483 mono_dynamic_image_release_gc_roots (MonoDynamicImage
*image
)
485 release_hashtable (&image
->token_fixups
);
486 release_hashtable (&image
->tokens
);
487 release_hashtable (&image
->remapped_tokens
);
488 release_hashtable (&image
->generic_def_objects
);
491 // Free dynamic image pass one: Free resources but not image itself
493 mono_dynamic_image_free (MonoDynamicImage
*image
)
495 MonoDynamicImage
*di
= image
;
500 g_hash_table_destroy (di
->typespec
);
502 g_hash_table_destroy (di
->typeref
);
504 g_hash_table_destroy (di
->handleref
);
506 mono_g_hash_table_destroy (di
->tokens
);
507 if (di
->remapped_tokens
)
508 mono_g_hash_table_destroy (di
->remapped_tokens
);
509 if (di
->generic_def_objects
)
510 mono_g_hash_table_destroy (di
->generic_def_objects
);
511 if (di
->blob_cache
) {
512 g_hash_table_foreach (di
->blob_cache
, free_blob_cache_entry
, NULL
);
513 g_hash_table_destroy (di
->blob_cache
);
515 if (di
->standalonesig_cache
)
516 g_hash_table_destroy (di
->standalonesig_cache
);
517 for (list
= di
->array_methods
; list
; list
= list
->next
) {
518 ArrayMethod
*am
= (ArrayMethod
*)list
->data
;
519 mono_sre_array_method_free (am
);
521 g_list_free (di
->array_methods
);
522 if (di
->gen_params
) {
523 for (i
= 0; i
< di
->gen_params
->len
; i
++) {
524 GenericParamTableEntry
*entry
= (GenericParamTableEntry
*)g_ptr_array_index (di
->gen_params
, i
);
525 mono_sre_generic_param_table_entry_free (entry
);
527 g_ptr_array_free (di
->gen_params
, TRUE
);
529 if (di
->token_fixups
)
530 mono_g_hash_table_destroy (di
->token_fixups
);
531 if (di
->method_to_table_idx
)
532 g_hash_table_destroy (di
->method_to_table_idx
);
533 if (di
->field_to_table_idx
)
534 g_hash_table_destroy (di
->field_to_table_idx
);
535 if (di
->method_aux_hash
)
536 g_hash_table_destroy (di
->method_aux_hash
);
537 if (di
->vararg_aux_hash
)
538 g_hash_table_destroy (di
->vararg_aux_hash
);
539 g_free (di
->strong_name
);
540 g_free (di
->win32_res
);
542 g_free (di
->public_key
);
544 /*g_print ("string heap destroy for image %p\n", di);*/
545 mono_dynamic_stream_reset (&di
->sheap
);
546 mono_dynamic_stream_reset (&di
->code
);
547 mono_dynamic_stream_reset (&di
->resources
);
548 mono_dynamic_stream_reset (&di
->us
);
549 mono_dynamic_stream_reset (&di
->blob
);
550 mono_dynamic_stream_reset (&di
->tstream
);
551 mono_dynamic_stream_reset (&di
->guid
);
552 for (i
= 0; i
< MONO_TABLE_NUM
; ++i
) {
553 g_free (di
->tables
[i
].values
);
556 dynamic_images_lock ();
559 g_ptr_array_remove (dynamic_images
, di
);
561 dynamic_images_unlock ();
564 // Free dynamic image pass two: Free image itself (might never get called in some debug modes)
566 mono_dynamic_image_free_image (MonoDynamicImage
*image
)