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_warning ("%s: Unexpected previous object when called with MONO_DYN_IMAGE_TOK_NEW", __func__
);
209 case MONO_DYN_IMAGE_TOK_SAME_OK
:
210 if (prev
!= MONO_HANDLE_RAW (obj
)) {
211 g_warning ("%s: condition `prev == MONO_HANDLE_RAW (obj)' not met", __func__
);
214 case MONO_DYN_IMAGE_TOK_REPLACE
:
217 g_assert_not_reached ();
220 mono_g_hash_table_insert (assembly
->tokens
, GUINT_TO_POINTER (token
), MONO_HANDLE_RAW (obj
));
221 dynamic_image_unlock (assembly
);
225 mono_dynamic_image_register_token (MonoDynamicImage
*assembly
, guint32 token
, MonoObjectHandle obj
, int how_collide
)
231 lookup_dyn_token (MonoDynamicImage
*assembly
, guint32 token
)
233 MONO_REQ_GC_UNSAFE_MODE
;
237 dynamic_image_lock (assembly
);
238 obj
= (MonoObject
*)mono_g_hash_table_lookup (assembly
->tokens
, GUINT_TO_POINTER (token
));
239 dynamic_image_unlock (assembly
);
244 #ifndef DISABLE_REFLECTION_EMIT
246 mono_dynamic_image_get_registered_token (MonoDynamicImage
*dynimage
, guint32 token
, MonoError
*error
)
249 return MONO_HANDLE_NEW (MonoObject
, lookup_dyn_token (dynimage
, token
));
251 #else /* DISABLE_REFLECTION_EMIT */
253 mono_dynamic_image_get_registered_token (MonoDynamicImage
*dynimage
, guint32 token
, MonoError
*error
)
255 g_assert_not_reached ();
262 * mono_dynamic_image_is_valid_token:
264 * Returns TRUE if token is valid in the given image.
268 mono_dynamic_image_is_valid_token (MonoDynamicImage
*image
, guint32 token
)
270 return lookup_dyn_token (image
, token
) != NULL
;
273 #ifndef DISABLE_REFLECTION_EMIT
275 #endif /* DISABLE_REFLECTION_EMIT */
277 #ifndef DISABLE_REFLECTION_EMIT
279 * mono_reflection_lookup_dynamic_token:
281 * Finish the Builder object pointed to by TOKEN and return the corresponding
282 * runtime structure. If HANDLE_CLASS is not NULL, it is set to the class required by
283 * mono_ldtoken. If valid_token is TRUE, assert if it is not found in the token->object
286 * LOCKING: Take the loader lock
289 mono_reflection_lookup_dynamic_token (MonoImage
*image
, guint32 token
, gboolean valid_token
, MonoClass
**handle_class
, MonoGenericContext
*context
, MonoError
*error
)
291 MonoDynamicImage
*assembly
= (MonoDynamicImage
*)image
;
297 obj
= lookup_dyn_token (assembly
, token
);
300 g_error ("Could not find required dynamic token 0x%08x", token
);
302 mono_error_set_execution_engine (error
, "Could not find dynamic token 0x%08x", token
);
308 handle_class
= &klass
;
309 gpointer result
= mono_reflection_resolve_object (image
, obj
, handle_class
, context
, error
);
312 #else /* DISABLE_REFLECTION_EMIT */
314 mono_reflection_lookup_dynamic_token (MonoImage
*image
, guint32 token
, gboolean valid_token
, MonoClass
**handle_class
, MonoGenericContext
*context
, MonoError
*error
)
319 #endif /* DISABLE_REFLECTION_EMIT */
321 #ifndef DISABLE_REFLECTION_EMIT
323 mono_dynamic_image_create (MonoDynamicAssembly
*assembly
, char *assembly_name
, char *module_name
)
325 static const guchar entrycode
[16] = {0xff, 0x25, 0};
326 MonoDynamicImage
*image
;
331 if (!strcmp (mono_get_runtime_info ()->framework_version
, "2.1"))
332 version
= "v2.0.50727"; /* HACK: SL 2 enforces the .net 2 metadata version */
334 version
= mono_get_runtime_info ()->runtime_version
;
337 /* The MonoGHashTable's need GC tracking */
338 image
= (MonoDynamicImage
*)GC_MALLOC (sizeof (MonoDynamicImage
));
340 image
= g_new0 (MonoDynamicImage
, 1);
343 mono_profiler_module_event (&image
->image
, MONO_PROFILE_START_LOAD
);
345 /*g_print ("created image %p\n", image);*/
346 /* keep in sync with image.c */
347 image
->image
.name
= assembly_name
;
348 image
->image
.assembly_name
= image
->image
.name
; /* they may be different */
349 image
->image
.module_name
= module_name
;
350 image
->image
.version
= g_strdup (version
);
351 image
->image
.md_version_major
= 1;
352 image
->image
.md_version_minor
= 1;
353 image
->image
.dynamic
= TRUE
;
355 image
->image
.references
= g_new0 (MonoAssembly
*, 1);
356 image
->image
.references
[0] = NULL
;
358 mono_image_init (&image
->image
);
360 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");
361 image
->method_to_table_idx
= g_hash_table_new (NULL
, NULL
);
362 image
->field_to_table_idx
= g_hash_table_new (NULL
, NULL
);
363 image
->method_aux_hash
= g_hash_table_new (NULL
, NULL
);
364 image
->vararg_aux_hash
= g_hash_table_new (NULL
, NULL
);
365 image
->handleref
= g_hash_table_new (NULL
, NULL
);
366 image
->tokens
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_VALUE_GC
, MONO_ROOT_SOURCE_REFLECTION
, "dynamic module tokens table");
367 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");
368 image
->typespec
= g_hash_table_new ((GHashFunc
)mono_metadata_type_hash
, (GCompareFunc
)mono_metadata_type_equal
);
369 image
->typeref
= g_hash_table_new ((GHashFunc
)mono_metadata_type_hash
, (GCompareFunc
)mono_metadata_type_equal
);
370 image
->blob_cache
= g_hash_table_new ((GHashFunc
)mono_blob_entry_hash
, (GCompareFunc
)mono_blob_entry_equal
);
371 image
->gen_params
= g_ptr_array_new ();
372 image
->remapped_tokens
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_VALUE_GC
, MONO_ROOT_SOURCE_REFLECTION
, "dynamic module remapped tokens table");
374 /*g_print ("string heap create for image %p (%s)\n", image, module_name);*/
375 string_heap_init (&image
->sheap
);
376 mono_dynstream_add_data (&image
->us
, "", 1);
377 mono_dynamic_image_add_to_blob_cached (image
, (char*) "", 1, NULL
, 0);
378 /* import tables... */
379 mono_dynstream_add_data (&image
->code
, (char*)entrycode
, sizeof (entrycode
));
380 image
->iat_offset
= mono_dynstream_add_zero (&image
->code
, 8); /* two IAT entries */
381 image
->idt_offset
= mono_dynstream_add_zero (&image
->code
, 2 * sizeof (MonoIDT
)); /* two IDT entries */
382 image
->imp_names_offset
= mono_dynstream_add_zero (&image
->code
, 2); /* flags for name entry */
383 mono_dynstream_add_data (&image
->code
, "_CorExeMain", 12);
384 mono_dynstream_add_data (&image
->code
, "mscoree.dll", 12);
385 image
->ilt_offset
= mono_dynstream_add_zero (&image
->code
, 8); /* two ILT entries */
386 mono_dynstream_data_align (&image
->code
);
388 image
->cli_header_offset
= mono_dynstream_add_zero (&image
->code
, sizeof (MonoCLIHeader
));
390 for (i
=0; i
< MONO_TABLE_NUM
; ++i
) {
391 image
->tables
[i
].next_idx
= 1;
392 image
->tables
[i
].columns
= table_sizes
[i
];
395 image
->image
.assembly
= (MonoAssembly
*)assembly
;
396 image
->run
= assembly
->run
;
397 image
->save
= assembly
->save
;
398 image
->pe_kind
= 0x1; /* ILOnly */
399 image
->machine
= 0x14c; /* I386 */
401 mono_profiler_module_loaded (&image
->image
, MONO_PROFILE_OK
);
403 dynamic_images_lock ();
406 dynamic_images
= g_ptr_array_new ();
408 g_ptr_array_add (dynamic_images
, image
);
410 dynamic_images_unlock ();
414 #else /* DISABLE_REFLECTION_EMIT */
416 mono_dynamic_image_create (MonoDynamicAssembly
*assembly
, char *assembly_name
, char *module_name
)
418 g_assert_not_reached ();
421 #endif /* DISABLE_REFLECTION_EMIT */
424 mono_dynamic_image_add_to_blob_cached (MonoDynamicImage
*assembly
, char *b1
, int s1
, char *b2
, int s2
)
426 MONO_REQ_GC_NEUTRAL_MODE
;
430 gpointer oldkey
, oldval
;
432 copy
= (char *)g_malloc (s1
+s2
);
433 memcpy (copy
, b1
, s1
);
434 memcpy (copy
+ s1
, b2
, s2
);
435 if (g_hash_table_lookup_extended (assembly
->blob_cache
, copy
, &oldkey
, &oldval
)) {
437 idx
= GPOINTER_TO_UINT (oldval
);
439 idx
= mono_dynstream_add_data (&assembly
->blob
, b1
, s1
);
440 mono_dynstream_add_data (&assembly
->blob
, b2
, s2
);
441 g_hash_table_insert (assembly
->blob_cache
, copy
, GUINT_TO_POINTER (idx
));
447 mono_dynimage_alloc_table (MonoDynamicTable
*table
, guint nrows
)
449 MONO_REQ_GC_NEUTRAL_MODE
;
452 g_assert (table
->columns
);
453 if (nrows
+ 1 >= table
->alloc_rows
) {
454 while (nrows
+ 1 >= table
->alloc_rows
) {
455 if (table
->alloc_rows
== 0)
456 table
->alloc_rows
= 16;
458 table
->alloc_rows
*= 2;
461 table
->values
= (guint32
*)g_renew (guint32
, table
->values
, (table
->alloc_rows
) * table
->columns
);
467 free_blob_cache_entry (gpointer key
, gpointer val
, gpointer user_data
)
473 release_hashtable (MonoGHashTable
**hash
)
476 mono_g_hash_table_destroy (*hash
);
482 mono_dynamic_image_release_gc_roots (MonoDynamicImage
*image
)
484 release_hashtable (&image
->token_fixups
);
485 release_hashtable (&image
->tokens
);
486 release_hashtable (&image
->remapped_tokens
);
487 release_hashtable (&image
->generic_def_objects
);
490 // Free dynamic image pass one: Free resources but not image itself
492 mono_dynamic_image_free (MonoDynamicImage
*image
)
494 MonoDynamicImage
*di
= image
;
499 g_hash_table_destroy (di
->typespec
);
501 g_hash_table_destroy (di
->typeref
);
503 g_hash_table_destroy (di
->handleref
);
505 mono_g_hash_table_destroy (di
->tokens
);
506 if (di
->remapped_tokens
)
507 mono_g_hash_table_destroy (di
->remapped_tokens
);
508 if (di
->generic_def_objects
)
509 mono_g_hash_table_destroy (di
->generic_def_objects
);
510 if (di
->blob_cache
) {
511 g_hash_table_foreach (di
->blob_cache
, free_blob_cache_entry
, NULL
);
512 g_hash_table_destroy (di
->blob_cache
);
514 if (di
->standalonesig_cache
)
515 g_hash_table_destroy (di
->standalonesig_cache
);
516 for (list
= di
->array_methods
; list
; list
= list
->next
) {
517 ArrayMethod
*am
= (ArrayMethod
*)list
->data
;
518 mono_sre_array_method_free (am
);
520 g_list_free (di
->array_methods
);
521 if (di
->gen_params
) {
522 for (i
= 0; i
< di
->gen_params
->len
; i
++) {
523 GenericParamTableEntry
*entry
= (GenericParamTableEntry
*)g_ptr_array_index (di
->gen_params
, i
);
524 mono_sre_generic_param_table_entry_free (entry
);
526 g_ptr_array_free (di
->gen_params
, TRUE
);
528 if (di
->token_fixups
)
529 mono_g_hash_table_destroy (di
->token_fixups
);
530 if (di
->method_to_table_idx
)
531 g_hash_table_destroy (di
->method_to_table_idx
);
532 if (di
->field_to_table_idx
)
533 g_hash_table_destroy (di
->field_to_table_idx
);
534 if (di
->method_aux_hash
)
535 g_hash_table_destroy (di
->method_aux_hash
);
536 if (di
->vararg_aux_hash
)
537 g_hash_table_destroy (di
->vararg_aux_hash
);
538 g_free (di
->strong_name
);
539 g_free (di
->win32_res
);
541 g_free (di
->public_key
);
543 /*g_print ("string heap destroy for image %p\n", di);*/
544 mono_dynamic_stream_reset (&di
->sheap
);
545 mono_dynamic_stream_reset (&di
->code
);
546 mono_dynamic_stream_reset (&di
->resources
);
547 mono_dynamic_stream_reset (&di
->us
);
548 mono_dynamic_stream_reset (&di
->blob
);
549 mono_dynamic_stream_reset (&di
->tstream
);
550 mono_dynamic_stream_reset (&di
->guid
);
551 for (i
= 0; i
< MONO_TABLE_NUM
; ++i
) {
552 g_free (di
->tables
[i
].values
);
555 dynamic_images_lock ();
558 g_ptr_array_remove (dynamic_images
, di
);
560 dynamic_images_unlock ();
563 // Free dynamic image pass two: Free image itself (might never get called in some debug modes)
565 mono_dynamic_image_free_image (MonoDynamicImage
*image
)
567 /* See create_dynamic_mono_image () */
569 /* Allocated using GC_MALLOC */