[mini] Use C++ linker iff building C++ that needs the C++ runtime (#12266)
[mono-project.git] / mono / metadata / dynamic-image.c
blobdfc682a8640ddd421171f30532af7fef8756e8cf
1 /**
2 * \file
3 * Images created at runtime.
4 *
5 *
6 * Author:
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.
17 #include <config.h>
18 #include <glib.h>
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;
35 static inline void
36 dynamic_images_lock (void)
38 mono_os_mutex_lock (&dynamic_images_mutex);
41 static inline void
42 dynamic_images_unlock (void)
44 mono_os_mutex_unlock (&dynamic_images_mutex);
47 void
48 mono_dynamic_images_init (void)
50 mono_os_mutex_init (&dynamic_images_mutex);
53 #ifndef DISABLE_REFLECTION_EMIT
54 static void
55 string_heap_init (MonoDynamicStream *sh)
57 mono_dynstream_init (sh);
59 #endif
61 #ifndef DISABLE_REFLECTION_EMIT
62 static int
63 mono_blob_entry_hash (const char* str)
65 MONO_REQ_GC_NEUTRAL_MODE;
67 guint len, h;
68 const char *end;
69 len = mono_metadata_decode_blob_size (str, &str);
70 if (len > 0) {
71 end = str + len;
72 h = *str;
73 for (str += 1; str < end; str++)
74 h = (h << 5) - h + *str;
75 return h;
76 } else {
77 return 0;
81 static gboolean
82 mono_blob_entry_equal (const char *str1, const char *str2) {
83 MONO_REQ_GC_NEUTRAL_MODE;
85 int len, len2;
86 const char *end1;
87 const char *end2;
88 len = mono_metadata_decode_blob_size (str1, &end1);
89 len2 = mono_metadata_decode_blob_size (str2, &end2);
90 if (len != len2)
91 return 0;
92 return memcmp (end1, end2, len) == 0;
94 #endif
97 /**
98 * mono_find_dynamic_image_owner:
100 * Find the dynamic image, if any, which a given pointer is located in the memory of.
102 MonoImage *
103 mono_find_dynamic_image_owner (void *ptr)
105 MonoImage *owner = NULL;
106 int i;
108 dynamic_images_lock ();
110 if (dynamic_images)
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))
115 owner = image;
119 dynamic_images_unlock ();
121 return owner;
124 static inline void
125 dynamic_image_lock (MonoDynamicImage *image)
127 MONO_ENTER_GC_SAFE;
128 mono_image_lock ((MonoImage*)image);
129 MONO_EXIT_GC_SAFE;
132 static inline void
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.
145 void
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));
154 if (prev) {
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__);
158 break;
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__);
163 break;
164 case MONO_DYN_IMAGE_TOK_REPLACE:
165 break;
166 default:
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);
173 #else
174 void
175 mono_dynamic_image_register_token (MonoDynamicImage *assembly, guint32 token, MonoObjectHandle obj, int how_collide)
178 #endif
180 static gboolean
181 lookup_dyn_token (MonoDynamicImage *assembly, guint32 token, MonoObjectHandle *object_handle)
183 MONO_REQ_GC_UNSAFE_MODE;
185 MonoObject *obj;
187 dynamic_image_lock (assembly);
188 obj = (MonoObject *)mono_g_hash_table_lookup (assembly->tokens, GUINT_TO_POINTER (token));
189 dynamic_image_unlock (assembly);
191 if (object_handle)
192 *object_handle = MONO_HANDLE_NEW (MonoObject, obj);
194 return obj != NULL;
197 #ifndef DISABLE_REFLECTION_EMIT
198 MonoObjectHandle
199 mono_dynamic_image_get_registered_token (MonoDynamicImage *dynimage, guint32 token, MonoError *error)
201 MonoObjectHandle obj;
202 lookup_dyn_token (dynimage, token, &obj);
203 return obj;
205 #else /* DISABLE_REFLECTION_EMIT */
206 MonoObjectHandle
207 mono_dynamic_image_get_registered_token (MonoDynamicImage *dynimage, guint32 token, MonoError *error)
209 g_assert_not_reached ();
210 return NULL_HANDLE;
212 #endif
216 * mono_dynamic_image_is_valid_token:
218 * Returns TRUE if token is valid in the given image.
221 gboolean
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
238 * mapping table.
240 * LOCKING: Take the loader lock
242 gpointer
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;
249 MonoClass *klass;
251 error_init (error);
253 lookup_dyn_token (assembly, token, &obj);
254 if (MONO_HANDLE_IS_NULL (obj)) {
255 if (valid_token)
256 g_error ("Could not find required dynamic token 0x%08x", token);
257 else {
258 mono_error_set_execution_engine (error, "Could not find dynamic token 0x%08x", token);
259 return NULL;
263 if (!handle_class)
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 */
269 gpointer
270 mono_reflection_lookup_dynamic_token (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context, MonoError *error)
272 error_init (error);
273 return NULL;
275 #endif /* DISABLE_REFLECTION_EMIT */
277 #ifndef DISABLE_REFLECTION_EMIT
279 static const unsigned char table_sizes [MONO_TABLE_NUM] = {
280 MONO_MODULE_SIZE,
281 MONO_TYPEREF_SIZE,
282 MONO_TYPEDEF_SIZE,
284 MONO_FIELD_SIZE,
286 MONO_METHOD_SIZE,
288 MONO_PARAM_SIZE,
289 MONO_INTERFACEIMPL_SIZE,
290 MONO_MEMBERREF_SIZE, /* 0x0A */
291 MONO_CONSTANT_SIZE,
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,
298 MONO_EVENT_MAP_SIZE,
300 MONO_EVENT_SIZE,
301 MONO_PROPERTY_MAP_SIZE,
303 MONO_PROPERTY_SIZE,
304 MONO_METHOD_SEMA_SIZE,
305 MONO_METHODIMPL_SIZE,
306 MONO_MODULEREF_SIZE, /* 0x1A */
307 MONO_TYPESPEC_SIZE,
308 MONO_IMPLMAP_SIZE,
309 MONO_FIELD_RVA_SIZE,
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,
318 MONO_FILE_SIZE,
319 MONO_EXP_TYPE_SIZE,
320 MONO_MANIFEST_SIZE,
321 MONO_NESTED_CLASS_SIZE,
323 MONO_GENERICPARAM_SIZE, /* 0x2A */
324 MONO_METHODSPEC_SIZE,
325 MONO_GENPARCONSTRAINT_SIZE
328 MonoDynamicImage*
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;
333 int i;
335 const char *version;
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 */
339 else
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 ();
406 if (!dynamic_images)
407 dynamic_images = g_ptr_array_new ();
409 g_ptr_array_add (dynamic_images, image);
411 dynamic_images_unlock ();
413 return image;
415 #else /* DISABLE_REFLECTION_EMIT */
416 MonoDynamicImage*
417 mono_dynamic_image_create (MonoDynamicAssembly *assembly, char *assembly_name, char *module_name)
419 g_assert_not_reached ();
420 return NULL;
422 #endif /* DISABLE_REFLECTION_EMIT */
424 guint32
425 mono_dynamic_image_add_to_blob_cached (MonoDynamicImage *assembly, gconstpointer b1, int s1, gconstpointer b2, int s2)
427 MONO_REQ_GC_NEUTRAL_MODE;
429 guint32 idx;
430 char *copy;
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)) {
437 g_free (copy);
438 idx = GPOINTER_TO_UINT (oldval);
439 } else {
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));
444 return idx;
447 void
448 mono_dynimage_alloc_table (MonoDynamicTable *table, guint nrows)
450 MONO_REQ_GC_NEUTRAL_MODE;
452 table->rows = nrows;
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;
458 else
459 table->alloc_rows *= 2;
462 table->values = (guint32 *)g_renew (guint32, table->values, (table->alloc_rows) * table->columns);
467 static void
468 free_blob_cache_entry (gpointer key, gpointer val, gpointer user_data)
470 g_free (key);
473 static void
474 release_hashtable (MonoGHashTable **hash)
476 if (*hash) {
477 mono_g_hash_table_destroy (*hash);
478 *hash = NULL;
482 void
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
492 void
493 mono_dynamic_image_free (MonoDynamicImage *image)
495 MonoDynamicImage *di = image;
496 GList *list;
497 int i;
499 if (di->typespec)
500 g_hash_table_destroy (di->typespec);
501 if (di->typeref)
502 g_hash_table_destroy (di->typeref);
503 if (di->handleref)
504 g_hash_table_destroy (di->handleref);
505 if (di->tokens)
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);
541 if (di->public_key)
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 ();
558 if (dynamic_images)
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)
565 void
566 mono_dynamic_image_free_image (MonoDynamicImage *image)
568 g_free (image);