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/mono-hash-internals.h"
25 #include "mono/metadata/profiler-private.h"
26 #include "mono/metadata/reflection-internals.h"
27 #include "mono/metadata/sre-internals.h"
28 #include "mono/utils/checked-build.h"
29 #include "mono/utils/mono-error-internals.h"
30 #include "mono/utils/mono-os-mutex.h"
32 // The dynamic images list is only needed to support the mempool reference tracking feature in checked-build.
33 static GPtrArray
*dynamic_images
;
34 static mono_mutex_t dynamic_images_mutex
;
37 dynamic_images_lock (void)
39 mono_os_mutex_lock (&dynamic_images_mutex
);
43 dynamic_images_unlock (void)
45 mono_os_mutex_unlock (&dynamic_images_mutex
);
49 mono_dynamic_images_init (void)
51 mono_os_mutex_init (&dynamic_images_mutex
);
54 #ifndef DISABLE_REFLECTION_EMIT
56 string_heap_init (MonoDynamicStream
*sh
)
58 mono_dynstream_init (sh
);
62 #ifndef DISABLE_REFLECTION_EMIT
64 mono_blob_entry_hash (const char* str
)
66 MONO_REQ_GC_NEUTRAL_MODE
;
70 len
= mono_metadata_decode_blob_size (str
, &str
);
74 for (str
+= 1; str
< end
; str
++)
75 h
= (h
<< 5) - h
+ *str
;
83 mono_blob_entry_equal (const char *str1
, const char *str2
) {
84 MONO_REQ_GC_NEUTRAL_MODE
;
89 len
= mono_metadata_decode_blob_size (str1
, &end1
);
90 len2
= mono_metadata_decode_blob_size (str2
, &end2
);
93 return memcmp (end1
, end2
, len
) == 0;
99 * mono_find_dynamic_image_owner:
101 * Find the dynamic image, if any, which a given pointer is located in the memory of.
104 mono_find_dynamic_image_owner (void *ptr
)
106 MonoImage
*owner
= NULL
;
109 dynamic_images_lock ();
113 for (i
= 0; !owner
&& i
< dynamic_images
->len
; ++i
) {
114 MonoImage
*image
= (MonoImage
*)g_ptr_array_index (dynamic_images
, i
);
115 if (mono_mempool_contains_addr (image
->mempool
, ptr
))
120 dynamic_images_unlock ();
126 dynamic_image_lock (MonoDynamicImage
*image
)
129 mono_image_lock ((MonoImage
*)image
);
134 dynamic_image_unlock (MonoDynamicImage
*image
)
136 mono_image_unlock ((MonoImage
*)image
);
139 #ifndef DISABLE_REFLECTION_EMIT
141 * mono_dynamic_image_register_token:
143 * Register the TOKEN->OBJ mapping in the mapping table in ASSEMBLY. This is required for
144 * the Module.ResolveXXXToken () methods to work.
147 mono_dynamic_image_register_token (MonoDynamicImage
*assembly
, guint32 token
, MonoObjectHandle obj
, int how_collide
)
149 MONO_REQ_GC_UNSAFE_MODE
;
151 g_assert (!MONO_HANDLE_IS_NULL (obj
));
152 g_assert (strcmp (m_class_get_name (mono_handle_class (obj
)), "EnumBuilder"));
153 dynamic_image_lock (assembly
);
154 MonoObject
*prev
= (MonoObject
*)mono_g_hash_table_lookup (assembly
->tokens
, GUINT_TO_POINTER (token
));
156 switch (how_collide
) {
157 case MONO_DYN_IMAGE_TOK_NEW
:
158 g_warning ("%s: Unexpected previous object when called with MONO_DYN_IMAGE_TOK_NEW", __func__
);
160 case MONO_DYN_IMAGE_TOK_SAME_OK
:
161 if (prev
!= MONO_HANDLE_RAW (obj
)) {
162 g_warning ("%s: condition `prev == MONO_HANDLE_RAW (obj)' not met", __func__
);
165 case MONO_DYN_IMAGE_TOK_REPLACE
:
168 g_assert_not_reached ();
171 mono_g_hash_table_insert_internal (assembly
->tokens
, GUINT_TO_POINTER (token
), MONO_HANDLE_RAW (obj
));
172 dynamic_image_unlock (assembly
);
176 mono_dynamic_image_register_token (MonoDynamicImage
*assembly
, guint32 token
, MonoObjectHandle obj
, int how_collide
)
182 lookup_dyn_token (MonoDynamicImage
*assembly
, guint32 token
, MonoObjectHandle
*object_handle
)
184 MONO_REQ_GC_UNSAFE_MODE
;
188 dynamic_image_lock (assembly
);
189 obj
= (MonoObject
*)mono_g_hash_table_lookup (assembly
->tokens
, GUINT_TO_POINTER (token
));
190 dynamic_image_unlock (assembly
);
193 *object_handle
= MONO_HANDLE_NEW (MonoObject
, obj
);
198 #ifndef DISABLE_REFLECTION_EMIT
200 mono_dynamic_image_get_registered_token (MonoDynamicImage
*dynimage
, guint32 token
, MonoError
*error
)
202 MonoObjectHandle obj
;
203 lookup_dyn_token (dynimage
, token
, &obj
);
206 #else /* DISABLE_REFLECTION_EMIT */
208 mono_dynamic_image_get_registered_token (MonoDynamicImage
*dynimage
, guint32 token
, MonoError
*error
)
210 g_assert_not_reached ();
217 * mono_dynamic_image_is_valid_token:
219 * Returns TRUE if token is valid in the given image.
223 mono_dynamic_image_is_valid_token (MonoDynamicImage
*image
, guint32 token
)
225 return lookup_dyn_token (image
, token
, NULL
);
228 #ifndef DISABLE_REFLECTION_EMIT
230 #endif /* DISABLE_REFLECTION_EMIT */
232 #ifndef DISABLE_REFLECTION_EMIT
234 * mono_reflection_lookup_dynamic_token:
236 * Finish the Builder object pointed to by TOKEN and return the corresponding
237 * runtime structure. If HANDLE_CLASS is not NULL, it is set to the class required by
238 * mono_ldtoken. If valid_token is TRUE, assert if it is not found in the token->object
241 * LOCKING: Take the loader lock
244 mono_reflection_lookup_dynamic_token (MonoImage
*image
, guint32 token
, gboolean valid_token
, MonoClass
**handle_class
, MonoGenericContext
*context
, MonoError
*error
)
246 HANDLE_FUNCTION_ENTER ();
248 MonoDynamicImage
*assembly
= (MonoDynamicImage
*)image
;
249 MonoObjectHandle obj
;
254 lookup_dyn_token (assembly
, token
, &obj
);
255 if (MONO_HANDLE_IS_NULL (obj
)) {
257 g_error ("Could not find required dynamic token 0x%08x", token
);
259 mono_error_set_execution_engine (error
, "Could not find dynamic token 0x%08x", token
);
265 handle_class
= &klass
;
266 gpointer
const result
= mono_reflection_resolve_object_handle (image
, obj
, handle_class
, context
, error
);
267 HANDLE_FUNCTION_RETURN_VAL (result
);
269 #else /* DISABLE_REFLECTION_EMIT */
271 mono_reflection_lookup_dynamic_token (MonoImage
*image
, guint32 token
, gboolean valid_token
, MonoClass
**handle_class
, MonoGenericContext
*context
, MonoError
*error
)
276 #endif /* DISABLE_REFLECTION_EMIT */
278 #ifndef DISABLE_REFLECTION_EMIT
280 static const unsigned char table_sizes
[MONO_TABLE_NUM
] = {
290 MONO_INTERFACEIMPL_SIZE
,
291 MONO_MEMBERREF_SIZE
, /* 0x0A */
293 MONO_CUSTOM_ATTR_SIZE
,
294 MONO_FIELD_MARSHAL_SIZE
,
295 MONO_DECL_SECURITY_SIZE
,
296 MONO_CLASS_LAYOUT_SIZE
,
297 MONO_FIELD_LAYOUT_SIZE
, /* 0x10 */
298 MONO_STAND_ALONE_SIGNATURE_SIZE
,
302 MONO_PROPERTY_MAP_SIZE
,
305 MONO_METHOD_SEMA_SIZE
,
306 MONO_METHODIMPL_SIZE
,
307 MONO_MODULEREF_SIZE
, /* 0x1A */
313 MONO_ASSEMBLY_SIZE
, /* 0x20 */
314 MONO_ASSEMBLY_PROCESSOR_SIZE
,
315 MONO_ASSEMBLYOS_SIZE
,
316 MONO_ASSEMBLYREF_SIZE
,
317 MONO_ASSEMBLYREFPROC_SIZE
,
318 MONO_ASSEMBLYREFOS_SIZE
,
322 MONO_NESTED_CLASS_SIZE
,
324 MONO_GENERICPARAM_SIZE
, /* 0x2A */
325 MONO_METHODSPEC_SIZE
,
326 MONO_GENPARCONSTRAINT_SIZE
330 mono_dynamic_image_create (MonoDynamicAssembly
*assembly
, char *assembly_name
, char *module_name
)
332 static const guchar entrycode
[16] = {0xff, 0x25, 0};
333 MonoDynamicImage
*image
;
338 if (!strcmp (mono_get_runtime_info ()->framework_version
, "2.1"))
339 version
= "v2.0.50727"; /* HACK: SL 2 enforces the .net 2 metadata version */
341 version
= mono_get_runtime_info ()->runtime_version
;
343 image
= g_new0 (MonoDynamicImage
, 1);
345 MONO_PROFILER_RAISE (image_loading
, (&image
->image
));
347 /*g_print ("created image %p\n", image);*/
348 /* keep in sync with image.c */
349 image
->image
.name
= assembly_name
;
350 image
->image
.assembly_name
= image
->image
.name
; /* they may be different */
351 image
->image
.module_name
= module_name
;
352 image
->image
.version
= g_strdup (version
);
353 image
->image
.md_version_major
= 1;
354 image
->image
.md_version_minor
= 1;
355 image
->image
.dynamic
= TRUE
;
357 image
->image
.references
= g_new0 (MonoAssembly
*, 1);
358 image
->image
.references
[0] = NULL
;
360 mono_image_init (&image
->image
);
362 image
->token_fixups
= mono_g_hash_table_new_type_internal ((GHashFunc
)mono_object_hash_internal
, NULL
, MONO_HASH_KEY_GC
, MONO_ROOT_SOURCE_REFLECTION
, NULL
, "Reflection Dynamic Image Token Fixup Table");
363 image
->method_to_table_idx
= g_hash_table_new (NULL
, NULL
);
364 image
->field_to_table_idx
= g_hash_table_new (NULL
, NULL
);
365 image
->method_aux_hash
= g_hash_table_new (NULL
, NULL
);
366 image
->vararg_aux_hash
= g_hash_table_new (NULL
, NULL
);
367 image
->handleref
= g_hash_table_new (NULL
, NULL
);
368 image
->tokens
= mono_g_hash_table_new_type_internal (NULL
, NULL
, MONO_HASH_VALUE_GC
, MONO_ROOT_SOURCE_REFLECTION
, NULL
, "Reflection Dynamic Image Token Table");
369 image
->generic_def_objects
= mono_g_hash_table_new_type_internal (NULL
, NULL
, MONO_HASH_VALUE_GC
, MONO_ROOT_SOURCE_REFLECTION
, NULL
, "Reflection Dynamic Image Generic Definition Table");
370 image
->typespec
= g_hash_table_new ((GHashFunc
)mono_metadata_type_hash
, (GCompareFunc
)mono_metadata_type_equal
);
371 image
->typeref
= g_hash_table_new ((GHashFunc
)mono_metadata_type_hash
, (GCompareFunc
)mono_metadata_type_equal
);
372 image
->blob_cache
= g_hash_table_new ((GHashFunc
)mono_blob_entry_hash
, (GCompareFunc
)mono_blob_entry_equal
);
373 image
->gen_params
= g_ptr_array_new ();
374 image
->remapped_tokens
= mono_g_hash_table_new_type_internal (NULL
, NULL
, MONO_HASH_VALUE_GC
, MONO_ROOT_SOURCE_REFLECTION
, NULL
, "Reflection Dynamic Image Remapped Token Table");
376 /*g_print ("string heap create for image %p (%s)\n", image, module_name);*/
377 string_heap_init (&image
->sheap
);
378 mono_dynstream_add_data (&image
->us
, "", 1);
379 mono_dynamic_image_add_to_blob_cached (image
, "", 1, NULL
, 0);
380 /* import tables... */
381 mono_dynstream_add_data (&image
->code
, entrycode
, sizeof (entrycode
));
382 image
->iat_offset
= mono_dynstream_add_zero (&image
->code
, 8); /* two IAT entries */
383 image
->idt_offset
= mono_dynstream_add_zero (&image
->code
, 2 * sizeof (MonoIDT
)); /* two IDT entries */
384 image
->imp_names_offset
= mono_dynstream_add_zero (&image
->code
, 2); /* flags for name entry */
385 mono_dynstream_add_data (&image
->code
, "_CorExeMain", 12);
386 mono_dynstream_add_data (&image
->code
, "mscoree.dll", 12);
387 image
->ilt_offset
= mono_dynstream_add_zero (&image
->code
, 8); /* two ILT entries */
388 mono_dynstream_data_align (&image
->code
);
390 image
->cli_header_offset
= mono_dynstream_add_zero (&image
->code
, sizeof (MonoCLIHeader
));
392 for (i
=0; i
< MONO_TABLE_NUM
; ++i
) {
393 image
->tables
[i
].next_idx
= 1;
394 image
->tables
[i
].columns
= table_sizes
[i
];
397 image
->image
.assembly
= (MonoAssembly
*)assembly
;
398 image
->run
= assembly
->run
;
399 image
->save
= assembly
->save
;
400 image
->pe_kind
= 0x1; /* ILOnly */
401 image
->machine
= 0x14c; /* I386 */
403 MONO_PROFILER_RAISE (image_loaded
, (&image
->image
));
405 dynamic_images_lock ();
408 dynamic_images
= g_ptr_array_new ();
410 g_ptr_array_add (dynamic_images
, image
);
412 dynamic_images_unlock ();
416 #else /* DISABLE_REFLECTION_EMIT */
418 mono_dynamic_image_create (MonoDynamicAssembly
*assembly
, char *assembly_name
, char *module_name
)
420 g_assert_not_reached ();
423 #endif /* DISABLE_REFLECTION_EMIT */
426 mono_dynamic_image_add_to_blob_cached (MonoDynamicImage
*assembly
, gconstpointer b1
, int s1
, gconstpointer b2
, int s2
)
428 MONO_REQ_GC_NEUTRAL_MODE
;
432 gpointer oldkey
, oldval
;
434 copy
= (char *)g_malloc (s1
+s2
);
435 memcpy (copy
, b1
, s1
);
436 memcpy (copy
+ s1
, b2
, s2
);
437 if (g_hash_table_lookup_extended (assembly
->blob_cache
, copy
, &oldkey
, &oldval
)) {
439 idx
= GPOINTER_TO_UINT (oldval
);
441 idx
= mono_dynstream_add_data (&assembly
->blob
, b1
, s1
);
442 mono_dynstream_add_data (&assembly
->blob
, b2
, s2
);
443 g_hash_table_insert (assembly
->blob_cache
, copy
, GUINT_TO_POINTER (idx
));
449 mono_dynimage_alloc_table (MonoDynamicTable
*table
, guint nrows
)
451 MONO_REQ_GC_NEUTRAL_MODE
;
454 g_assert (table
->columns
);
455 if (nrows
+ 1 >= table
->alloc_rows
) {
456 while (nrows
+ 1 >= table
->alloc_rows
) {
457 if (table
->alloc_rows
== 0)
458 table
->alloc_rows
= 16;
460 table
->alloc_rows
*= 2;
463 table
->values
= (guint32
*)g_renew (guint32
, table
->values
, (table
->alloc_rows
) * table
->columns
);
469 free_blob_cache_entry (gpointer key
, gpointer val
, gpointer user_data
)
475 release_hashtable (MonoGHashTable
**hash
)
478 mono_g_hash_table_destroy (*hash
);
484 mono_dynamic_image_release_gc_roots (MonoDynamicImage
*image
)
486 release_hashtable (&image
->token_fixups
);
487 release_hashtable (&image
->tokens
);
488 release_hashtable (&image
->remapped_tokens
);
489 release_hashtable (&image
->generic_def_objects
);
492 // Free dynamic image pass one: Free resources but not image itself
494 mono_dynamic_image_free (MonoDynamicImage
*image
)
496 MonoDynamicImage
*di
= image
;
501 g_hash_table_destroy (di
->typespec
);
503 g_hash_table_destroy (di
->typeref
);
505 g_hash_table_destroy (di
->handleref
);
507 mono_g_hash_table_destroy (di
->tokens
);
508 if (di
->remapped_tokens
)
509 mono_g_hash_table_destroy (di
->remapped_tokens
);
510 if (di
->generic_def_objects
)
511 mono_g_hash_table_destroy (di
->generic_def_objects
);
512 if (di
->blob_cache
) {
513 g_hash_table_foreach (di
->blob_cache
, free_blob_cache_entry
, NULL
);
514 g_hash_table_destroy (di
->blob_cache
);
516 if (di
->standalonesig_cache
)
517 g_hash_table_destroy (di
->standalonesig_cache
);
518 for (list
= di
->array_methods
; list
; list
= list
->next
) {
519 ArrayMethod
*am
= (ArrayMethod
*)list
->data
;
520 mono_sre_array_method_free (am
);
522 g_list_free (di
->array_methods
);
523 if (di
->gen_params
) {
524 for (i
= 0; i
< di
->gen_params
->len
; i
++) {
525 GenericParamTableEntry
*entry
= (GenericParamTableEntry
*)g_ptr_array_index (di
->gen_params
, i
);
526 mono_sre_generic_param_table_entry_free (entry
);
528 g_ptr_array_free (di
->gen_params
, TRUE
);
530 if (di
->token_fixups
)
531 mono_g_hash_table_destroy (di
->token_fixups
);
532 if (di
->method_to_table_idx
)
533 g_hash_table_destroy (di
->method_to_table_idx
);
534 if (di
->field_to_table_idx
)
535 g_hash_table_destroy (di
->field_to_table_idx
);
536 if (di
->method_aux_hash
)
537 g_hash_table_destroy (di
->method_aux_hash
);
538 if (di
->vararg_aux_hash
)
539 g_hash_table_destroy (di
->vararg_aux_hash
);
540 g_free (di
->strong_name
);
541 g_free (di
->win32_res
);
543 g_free (di
->public_key
);
545 /*g_print ("string heap destroy for image %p\n", di);*/
546 mono_dynamic_stream_reset (&di
->sheap
);
547 mono_dynamic_stream_reset (&di
->code
);
548 mono_dynamic_stream_reset (&di
->resources
);
549 mono_dynamic_stream_reset (&di
->us
);
550 mono_dynamic_stream_reset (&di
->blob
);
551 mono_dynamic_stream_reset (&di
->tstream
);
552 mono_dynamic_stream_reset (&di
->guid
);
553 for (i
= 0; i
< MONO_TABLE_NUM
; ++i
) {
554 g_free (di
->tables
[i
].values
);
557 dynamic_images_lock ();
560 g_ptr_array_remove (dynamic_images
, di
);
562 dynamic_images_unlock ();
565 // Free dynamic image pass two: Free image itself (might never get called in some debug modes)
567 mono_dynamic_image_free_image (MonoDynamicImage
*image
)