2 * dynamic-image.c: Images created at runtime.
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.
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
] = {
40 MONO_INTERFACEIMPL_SIZE
,
41 MONO_MEMBERREF_SIZE
, /* 0x0A */
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
,
52 MONO_PROPERTY_MAP_SIZE
,
55 MONO_METHOD_SEMA_SIZE
,
57 MONO_MODULEREF_SIZE
, /* 0x1A */
63 MONO_ASSEMBLY_SIZE
, /* 0x20 */
64 MONO_ASSEMBLY_PROCESSOR_SIZE
,
66 MONO_ASSEMBLYREF_SIZE
,
67 MONO_ASSEMBLYREFPROC_SIZE
,
68 MONO_ASSEMBLYREFOS_SIZE
,
72 MONO_NESTED_CLASS_SIZE
,
74 MONO_GENERICPARAM_SIZE
, /* 0x2A */
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
;
85 dynamic_images_lock (void)
87 mono_os_mutex_lock (&dynamic_images_mutex
);
91 dynamic_images_unlock (void)
93 mono_os_mutex_unlock (&dynamic_images_mutex
);
97 mono_dynamic_images_init (void)
99 mono_os_mutex_init (&dynamic_images_mutex
);
102 #ifndef DISABLE_REFLECTION_EMIT
104 string_heap_init (MonoDynamicStream
*sh
)
106 mono_dynstream_init (sh
);
110 #ifndef DISABLE_REFLECTION_EMIT
112 mono_blob_entry_hash (const char* str
)
114 MONO_REQ_GC_NEUTRAL_MODE
;
118 len
= mono_metadata_decode_blob_size (str
, &str
);
122 for (str
+= 1; str
< end
; str
++)
123 h
= (h
<< 5) - h
+ *str
;
131 mono_blob_entry_equal (const char *str1
, const char *str2
) {
132 MONO_REQ_GC_NEUTRAL_MODE
;
137 len
= mono_metadata_decode_blob_size (str1
, &end1
);
138 len2
= mono_metadata_decode_blob_size (str2
, &end2
);
141 return memcmp (end1
, end2
, len
) == 0;
147 * mono_find_dynamic_image_owner:
149 * Find the dynamic image, if any, which a given pointer is located in the memory of.
152 mono_find_dynamic_image_owner (void *ptr
)
154 MonoImage
*owner
= NULL
;
157 dynamic_images_lock ();
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
))
168 dynamic_images_unlock ();
174 dynamic_image_lock (MonoDynamicImage
*image
)
177 mono_image_lock ((MonoImage
*)image
);
182 dynamic_image_unlock (MonoDynamicImage
*image
)
184 mono_image_unlock ((MonoImage
*)image
);
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
);
198 lookup_dyn_token (MonoDynamicImage
*assembly
, guint32 token
)
200 MONO_REQ_GC_UNSAFE_MODE
;
204 dynamic_image_lock (assembly
);
205 obj
= (MonoObject
*)mono_g_hash_table_lookup (assembly
->tokens
, GUINT_TO_POINTER (token
));
206 dynamic_image_unlock (assembly
);
213 * mono_dynamic_image_is_valid_token:
215 * Returns TRUE if token is valid in the given image.
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
237 * LOCKING: Take the loader lock
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
;
246 mono_error_init (error
);
248 obj
= lookup_dyn_token (assembly
, token
);
251 g_error ("Could not find required dynamic token 0x%08x", token
);
253 mono_error_set_execution_engine (error
, "Could not find dynamic token 0x%08x", token
);
259 handle_class
= &klass
;
260 gpointer result
= mono_reflection_resolve_object (image
, obj
, handle_class
, context
, error
);
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.
271 mono_image_register_token (MonoDynamicImage
*assembly
, guint32 token
, MonoObject
*obj
)
275 dynamic_image_lock (assembly
);
276 prev
= (MonoObject
*)mono_g_hash_table_lookup (assembly
->tokens
, GUINT_TO_POINTER (token
));
278 /* There could be multiple MethodInfo objects with the same token */
279 //g_assert (prev == obj);
281 mono_g_hash_table_insert (assembly
->tokens
, GUINT_TO_POINTER (token
), obj
);
283 dynamic_image_unlock (assembly
);
286 #else /* DISABLE_REFLECTION_EMIT */
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
);
296 mono_image_register_token (MonoDynamicImage
*assembly
, guint32 token
, MonoObject
*obj
)
300 #endif /* DISABLE_REFLECTION_EMIT */
302 #ifndef DISABLE_REFLECTION_EMIT
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
;
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 */
315 version
= mono_get_runtime_info ()->runtime_version
;
318 /* The MonoGHashTable's need GC tracking */
319 image
= (MonoDynamicImage
*)GC_MALLOC (sizeof (MonoDynamicImage
));
321 image
= g_new0 (MonoDynamicImage
, 1);
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 ();
388 dynamic_images
= g_ptr_array_new ();
390 g_ptr_array_add (dynamic_images
, image
);
392 dynamic_images_unlock ();
396 #else /* DISABLE_REFLECTION_EMIT */
398 mono_dynamic_image_create (MonoDynamicAssembly
*assembly
, char *assembly_name
, char *module_name
)
400 g_assert_not_reached ();
403 #endif /* DISABLE_REFLECTION_EMIT */
406 mono_dynamic_image_add_to_blob_cached (MonoDynamicImage
*assembly
, char *b1
, int s1
, char *b2
, int s2
)
408 MONO_REQ_GC_NEUTRAL_MODE
;
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
)) {
419 idx
= GPOINTER_TO_UINT (oldval
);
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
));
429 mono_dynimage_alloc_table (MonoDynamicTable
*table
, guint nrows
)
431 MONO_REQ_GC_NEUTRAL_MODE
;
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;
440 table
->alloc_rows
*= 2;
443 table
->values
= (guint32
*)g_renew (guint32
, table
->values
, (table
->alloc_rows
) * table
->columns
);
449 free_blob_cache_entry (gpointer key
, gpointer val
, gpointer user_data
)
455 release_hashtable (MonoGHashTable
**hash
)
458 mono_g_hash_table_destroy (*hash
);
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
475 mono_dynamic_image_free (MonoDynamicImage
*image
)
477 MonoDynamicImage
*di
= image
;
482 g_hash_table_destroy (di
->typespec
);
484 g_hash_table_destroy (di
->typeref
);
486 g_hash_table_destroy (di
->handleref
);
487 if (di
->handleref_managed
)
488 mono_g_hash_table_destroy (di
->handleref_managed
);
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
);
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 ();
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)
550 mono_dynamic_image_free_image (MonoDynamicImage
*image
)
552 /* See create_dynamic_mono_image () */
554 /* Allocated using GC_MALLOC */