[2020-02] Fix leak in assembly-specific dllmap lookups (#21053)
[mono-project.git] / mono / metadata / method-builder-ilgen.c
blob290d4f745a8d8994e74af49d8391fd6c101bb859
1 /**
2 * \file
3 * Copyright 2018 Microsoft
4 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
5 */
6 #include "config.h"
7 #include "loader.h"
8 #include "mono/metadata/abi-details.h"
9 #include "mono/metadata/method-builder.h"
10 #include "mono/metadata/method-builder-ilgen.h"
11 #include "mono/metadata/method-builder-ilgen-internals.h"
12 #include "mono/metadata/tabledefs.h"
13 #include "mono/metadata/exception.h"
14 #include "mono/metadata/appdomain.h"
15 #include "mono/metadata/debug-helpers.h"
16 #include "mono/metadata/metadata-internals.h"
17 #include "mono/metadata/domain-internals.h"
18 #include <string.h>
19 #include <errno.h>
20 #include "class-init.h"
22 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
23 a = i,
25 enum {
26 #include "mono/cil/opcode.def"
27 LAST = 0xff
29 #undef OPDEF
31 static MonoMethodBuilder *
32 new_base_ilgen (MonoClass *klass, MonoWrapperType type)
34 MonoMethodBuilder *mb;
35 MonoMethod *m;
37 g_assert (klass != NULL);
39 mb = g_new0 (MonoMethodBuilder, 1);
41 mb->method = m = (MonoMethod *)g_new0 (MonoMethodWrapper, 1);
43 m->klass = klass;
44 m->inline_info = 1;
45 m->wrapper_type = type;
47 mb->code_size = 40;
48 mb->code = (unsigned char *)g_malloc (mb->code_size);
49 mb->init_locals = TRUE;
51 /* placeholder for the wrapper always at index 1 */
52 mono_mb_add_data (mb, NULL);
54 return mb;
57 static void
58 free_ilgen (MonoMethodBuilder *mb)
60 GList *l;
62 for (l = mb->locals_list; l; l = l->next) {
63 /* Allocated in mono_mb_add_local () */
64 g_free (l->data);
66 g_list_free (mb->locals_list);
67 if (!mb->dynamic) {
68 g_free (mb->method);
69 if (!mb->no_dup_name)
70 g_free (mb->name);
71 g_free (mb->code);
73 g_free (mb);
76 static MonoMethod *
77 create_method_ilgen (MonoMethodBuilder *mb, MonoMethodSignature *signature, int max_stack)
79 MonoMethodHeader *header;
80 MonoMethodWrapper *mw;
81 MonoImage *image;
82 MonoMethod *method;
83 GList *l;
84 int i;
86 g_assert (mb != NULL);
88 image = m_class_get_image (mb->method->klass);
90 if (mb->dynamic) {
91 method = mb->method;
92 mw = (MonoMethodWrapper*)method;
94 method->name = mb->name;
95 method->dynamic = TRUE;
97 mw->header = header = (MonoMethodHeader *)
98 g_malloc0 (MONO_SIZEOF_METHOD_HEADER + mb->locals * sizeof (MonoType *));
100 header->code = mb->code;
102 for (i = 0, l = mb->locals_list; l; l = l->next, i++) {
103 header->locals [i] = (MonoType*)l->data;
105 } else
107 /* Realloc the method info into a mempool */
109 method = (MonoMethod *)mono_image_alloc0 (image, sizeof (MonoMethodWrapper));
110 memcpy (method, mb->method, sizeof (MonoMethodWrapper));
111 mw = (MonoMethodWrapper*) method;
113 if (mb->no_dup_name)
114 method->name = mb->name;
115 else
116 method->name = mono_image_strdup (image, mb->name);
118 mw->header = header = (MonoMethodHeader *)
119 mono_image_alloc0 (image, MONO_SIZEOF_METHOD_HEADER + mb->locals * sizeof (MonoType *));
121 header->code = (const unsigned char *)mono_image_alloc (image, mb->pos);
122 memcpy ((char*)header->code, mb->code, mb->pos);
124 for (i = 0, l = mb->locals_list; l; l = l->next, i++) {
125 header->locals [i] = (MonoType*)l->data;
129 /* Free the locals list so mono_mb_free () doesn't free the types twice */
130 g_list_free (mb->locals_list);
131 mb->locals_list = NULL;
133 method->signature = signature;
134 if (!signature->hasthis)
135 method->flags |= METHOD_ATTRIBUTE_STATIC;
137 if (max_stack < 8)
138 max_stack = 8;
140 header->max_stack = max_stack;
142 header->code_size = mb->pos;
143 header->num_locals = mb->locals;
144 header->init_locals = mb->init_locals;
145 header->volatile_args = mb->volatile_args;
146 header->volatile_locals = mb->volatile_locals;
147 mb->volatile_args = NULL;
148 mb->volatile_locals = NULL;
150 header->num_clauses = mb->num_clauses;
151 header->clauses = mb->clauses;
153 method->skip_visibility = mb->skip_visibility;
155 i = g_list_length ((GList *)mw->method_data);
156 if (i) {
157 GList *tmp;
158 void **data;
159 l = g_list_reverse ((GList *)mw->method_data);
160 if (method_is_dynamic (method))
161 data = (void **)g_malloc (sizeof (gpointer) * (i + 1));
162 else
163 data = (void **)mono_image_alloc (image, sizeof (gpointer) * (i + 1));
164 /* store the size in the first element */
165 data [0] = GUINT_TO_POINTER (i);
166 i = 1;
167 for (tmp = l; tmp; tmp = tmp->next) {
168 data [i++] = tmp->data;
170 g_list_free (l);
172 mw->method_data = data;
176 static int total_code = 0;
177 static int total_alloc = 0;
178 total_code += mb->pos;
179 total_alloc += mb->code_size;
180 g_print ("code size: %d of %d (allocated: %d)\n", mb->pos, total_code, total_alloc);
183 #ifdef DEBUG_RUNTIME_CODE
184 printf ("RUNTIME CODE FOR %s\n", mono_method_full_name (method, TRUE));
185 printf ("%s\n", mono_disasm_code (&marshal_dh, method, mb->code, mb->code + mb->pos));
186 #endif
188 if (mb->param_names) {
189 char **param_names = (char **)mono_image_alloc0 (image, signature->param_count * sizeof (gpointer));
190 for (i = 0; i < signature->param_count; ++i)
191 param_names [i] = mono_image_strdup (image, mb->param_names [i]);
193 mono_image_lock (image);
194 if (!image->wrapper_param_names)
195 image->wrapper_param_names = g_hash_table_new (NULL, NULL);
196 g_hash_table_insert (image->wrapper_param_names, method, param_names);
197 mono_image_unlock (image);
200 return method;
203 void
204 mono_method_builder_ilgen_init (void)
206 MonoMethodBuilderCallbacks cb;
207 cb.version = MONO_METHOD_BUILDER_CALLBACKS_VERSION;
208 cb.new_base = new_base_ilgen;
209 cb.free = free_ilgen;
210 cb.create_method = create_method_ilgen;
211 mono_install_method_builder_callbacks (&cb);
215 * mono_mb_add_local:
218 mono_mb_add_local (MonoMethodBuilder *mb, MonoType *type)
220 int res;
221 MonoType *t;
224 * Have to make a copy early since type might be sig->ret,
225 * which is transient, see mono_metadata_signature_dup_internal_with_padding ().
227 t = mono_metadata_type_dup (NULL, type);
229 g_assert (mb != NULL);
230 g_assert (type != NULL);
232 res = mb->locals;
233 mb->locals_list = g_list_append (mb->locals_list, t);
234 mb->locals++;
236 return res;
240 * mono_mb_patch_addr:
242 void
243 mono_mb_patch_addr (MonoMethodBuilder *mb, int pos, int value)
245 mb->code [pos] = value & 0xff;
246 mb->code [pos + 1] = (value >> 8) & 0xff;
247 mb->code [pos + 2] = (value >> 16) & 0xff;
248 mb->code [pos + 3] = (value >> 24) & 0xff;
252 * mono_mb_patch_addr_s:
254 void
255 mono_mb_patch_addr_s (MonoMethodBuilder *mb, int pos, gint8 value)
257 *((gint8 *)(&mb->code [pos])) = value;
261 * mono_mb_emit_byte:
263 void
264 mono_mb_emit_byte (MonoMethodBuilder *mb, guint8 op)
266 if (mb->pos >= mb->code_size) {
267 mb->code_size += mb->code_size >> 1;
268 mb->code = (unsigned char *)g_realloc (mb->code, mb->code_size);
271 mb->code [mb->pos++] = op;
275 * mono_mb_emit_ldflda:
277 void
278 mono_mb_emit_ldflda (MonoMethodBuilder *mb, gint32 offset)
280 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
281 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
283 if (offset) {
284 mono_mb_emit_icon (mb, offset);
285 mono_mb_emit_byte (mb, CEE_ADD);
290 * mono_mb_emit_i4:
292 void
293 mono_mb_emit_i4 (MonoMethodBuilder *mb, gint32 data)
295 if ((mb->pos + 4) >= mb->code_size) {
296 mb->code_size += mb->code_size >> 1;
297 mb->code = (unsigned char *)g_realloc (mb->code, mb->code_size);
300 mono_mb_patch_addr (mb, mb->pos, data);
301 mb->pos += 4;
304 void
305 mono_mb_emit_i8 (MonoMethodBuilder *mb, gint64 data)
307 if ((mb->pos + 8) >= mb->code_size) {
308 mb->code_size += mb->code_size >> 1;
309 mb->code = (unsigned char *)g_realloc (mb->code, mb->code_size);
312 mono_mb_patch_addr (mb, mb->pos, data);
313 mono_mb_patch_addr (mb, mb->pos + 4, data >> 32);
314 mb->pos += 8;
318 * mono_mb_emit_i2:
320 void
321 mono_mb_emit_i2 (MonoMethodBuilder *mb, gint16 data)
323 if ((mb->pos + 2) >= mb->code_size) {
324 mb->code_size += mb->code_size >> 1;
325 mb->code = (unsigned char *)g_realloc (mb->code, mb->code_size);
328 mb->code [mb->pos] = data & 0xff;
329 mb->code [mb->pos + 1] = (data >> 8) & 0xff;
330 mb->pos += 2;
333 void
334 mono_mb_emit_op (MonoMethodBuilder *mb, guint8 op, gpointer data)
336 mono_mb_emit_byte (mb, op);
337 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, data));
341 * mono_mb_emit_ldstr:
343 void
344 mono_mb_emit_ldstr (MonoMethodBuilder *mb, char *str)
346 mono_mb_emit_op (mb, CEE_LDSTR, str);
350 * mono_mb_emit_ldarg:
352 void
353 mono_mb_emit_ldarg (MonoMethodBuilder *mb, guint argnum)
355 if (argnum < 4) {
356 mono_mb_emit_byte (mb, CEE_LDARG_0 + argnum);
357 } else if (argnum < 256) {
358 mono_mb_emit_byte (mb, CEE_LDARG_S);
359 mono_mb_emit_byte (mb, argnum);
360 } else {
361 mono_mb_emit_byte (mb, CEE_PREFIX1);
362 mono_mb_emit_byte (mb, CEE_LDARG);
363 mono_mb_emit_i2 (mb, argnum);
368 * mono_mb_emit_ldarg_addr:
370 void
371 mono_mb_emit_ldarg_addr (MonoMethodBuilder *mb, guint argnum)
373 if (argnum < 256) {
374 mono_mb_emit_byte (mb, CEE_LDARGA_S);
375 mono_mb_emit_byte (mb, argnum);
376 } else {
377 mono_mb_emit_byte (mb, CEE_PREFIX1);
378 mono_mb_emit_byte (mb, CEE_LDARGA);
379 mono_mb_emit_i2 (mb, argnum);
384 * mono_mb_emit_ldloc_addr:
386 void
387 mono_mb_emit_ldloc_addr (MonoMethodBuilder *mb, guint locnum)
389 if (locnum < 256) {
390 mono_mb_emit_byte (mb, CEE_LDLOCA_S);
391 mono_mb_emit_byte (mb, locnum);
392 } else {
393 mono_mb_emit_byte (mb, CEE_PREFIX1);
394 mono_mb_emit_byte (mb, CEE_LDLOCA);
395 mono_mb_emit_i2 (mb, locnum);
400 * mono_mb_emit_ldloc:
402 void
403 mono_mb_emit_ldloc (MonoMethodBuilder *mb, guint num)
405 if (num < 4) {
406 mono_mb_emit_byte (mb, CEE_LDLOC_0 + num);
407 } else if (num < 256) {
408 mono_mb_emit_byte (mb, CEE_LDLOC_S);
409 mono_mb_emit_byte (mb, num);
410 } else {
411 mono_mb_emit_byte (mb, CEE_PREFIX1);
412 mono_mb_emit_byte (mb, CEE_LDLOC);
413 mono_mb_emit_i2 (mb, num);
418 * mono_mb_emit_stloc:
420 void
421 mono_mb_emit_stloc (MonoMethodBuilder *mb, guint num)
423 if (num < 4) {
424 mono_mb_emit_byte (mb, CEE_STLOC_0 + num);
425 } else if (num < 256) {
426 mono_mb_emit_byte (mb, CEE_STLOC_S);
427 mono_mb_emit_byte (mb, num);
428 } else {
429 mono_mb_emit_byte (mb, CEE_PREFIX1);
430 mono_mb_emit_byte (mb, CEE_STLOC);
431 mono_mb_emit_i2 (mb, num);
436 * mono_mb_emit_icon:
438 void
439 mono_mb_emit_icon (MonoMethodBuilder *mb, gint32 value)
441 if (value >= -1 && value < 8) {
442 mono_mb_emit_byte (mb, CEE_LDC_I4_0 + value);
443 } else if (value >= -128 && value <= 127) {
444 mono_mb_emit_byte (mb, CEE_LDC_I4_S);
445 mono_mb_emit_byte (mb, value);
446 } else {
447 mono_mb_emit_byte (mb, CEE_LDC_I4);
448 mono_mb_emit_i4 (mb, value);
452 void
453 mono_mb_emit_icon8 (MonoMethodBuilder *mb, gint64 value)
455 mono_mb_emit_byte (mb, CEE_LDC_I8);
456 mono_mb_emit_i8 (mb, value);
460 mono_mb_get_label (MonoMethodBuilder *mb)
462 return mb->pos;
466 mono_mb_get_pos (MonoMethodBuilder *mb)
468 return mb->pos;
472 * mono_mb_emit_branch:
474 guint32
475 mono_mb_emit_branch (MonoMethodBuilder *mb, guint8 op)
477 guint32 res;
478 mono_mb_emit_byte (mb, op);
479 res = mb->pos;
480 mono_mb_emit_i4 (mb, 0);
481 return res;
484 guint32
485 mono_mb_emit_short_branch (MonoMethodBuilder *mb, guint8 op)
487 guint32 res;
488 mono_mb_emit_byte (mb, op);
489 res = mb->pos;
490 mono_mb_emit_byte (mb, 0);
492 return res;
495 void
496 mono_mb_emit_branch_label (MonoMethodBuilder *mb, guint8 op, guint32 label)
498 mono_mb_emit_byte (mb, op);
499 mono_mb_emit_i4 (mb, label - (mb->pos + 4));
502 void
503 mono_mb_patch_branch (MonoMethodBuilder *mb, guint32 pos)
505 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
508 void
509 mono_mb_patch_short_branch (MonoMethodBuilder *mb, guint32 pos)
511 mono_mb_patch_addr_s (mb, pos, mb->pos - (pos + 1));
514 void
515 mono_mb_emit_ptr (MonoMethodBuilder *mb, gpointer ptr)
517 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
518 mono_mb_emit_op (mb, CEE_MONO_LDPTR, ptr);
521 void
522 mono_mb_emit_calli (MonoMethodBuilder *mb, MonoMethodSignature *sig)
524 mono_mb_emit_op (mb, CEE_CALLI, sig);
528 * mono_mb_emit_managed_call:
530 void
531 mono_mb_emit_managed_call (MonoMethodBuilder *mb, MonoMethod *method, MonoMethodSignature *opt_sig)
533 mono_mb_emit_op (mb, CEE_CALL, method);
537 * mono_mb_emit_native_call:
539 void
540 mono_mb_emit_native_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, gpointer func)
542 mono_mb_emit_ptr (mb, func);
543 mono_mb_emit_calli (mb, sig);
546 void
547 mono_mb_emit_icall_id (MonoMethodBuilder *mb, MonoJitICallId jit_icall_id)
549 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
550 mono_mb_emit_byte (mb, CEE_MONO_ICALL);
551 mono_mb_emit_i4 (mb, jit_icall_id);
554 void
555 mono_mb_emit_exception_full (MonoMethodBuilder *mb, const char *exc_nspace, const char *exc_name, const char *msg)
557 ERROR_DECL (error);
558 MonoMethod *ctor = NULL;
560 MonoClass *mme = mono_class_load_from_name (mono_defaults.corlib, exc_nspace, exc_name);
561 mono_class_init_internal (mme);
562 ctor = mono_class_get_method_from_name_checked (mme, ".ctor", 0, 0, error);
563 mono_error_assert_ok (error);
564 g_assert (ctor);
565 mono_mb_emit_op (mb, CEE_NEWOBJ, ctor);
566 if (msg != NULL) {
567 mono_mb_emit_byte (mb, CEE_DUP);
568 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoException, message));
569 mono_mb_emit_ldstr (mb, (char*)msg);
570 mono_mb_emit_byte (mb, CEE_STIND_REF);
572 mono_mb_emit_byte (mb, CEE_THROW);
576 * mono_mb_emit_exception:
578 void
579 mono_mb_emit_exception (MonoMethodBuilder *mb, const char *exc_name, const char *msg)
581 mono_mb_emit_exception_full (mb, "System", exc_name, msg);
585 * mono_mb_emit_exception_for_error:
587 void
588 mono_mb_emit_exception_for_error (MonoMethodBuilder *mb, MonoError *error)
591 * If at some point there is need to support other types of errors,
592 * the behaviour should conform with mono_error_prepare_exception().
594 g_assert (mono_error_get_error_code (error) == MONO_ERROR_GENERIC && "Unsupported error code.");
595 /* Have to copy the message because it will be referenced from JITed code while the MonoError may be freed. */
596 char *msg = mono_mb_strdup (mb, mono_error_get_message (error));
597 mono_mb_emit_exception_full (mb, "System", mono_error_get_exception_name (error), msg);
601 * mono_mb_emit_add_to_local:
603 void
604 mono_mb_emit_add_to_local (MonoMethodBuilder *mb, guint16 local, gint32 incr)
606 mono_mb_emit_ldloc (mb, local);
607 mono_mb_emit_icon (mb, incr);
608 mono_mb_emit_byte (mb, CEE_ADD);
609 mono_mb_emit_stloc (mb, local);
612 void
613 mono_mb_set_clauses (MonoMethodBuilder *mb, int num_clauses, MonoExceptionClause *clauses)
615 mb->num_clauses = num_clauses;
616 mb->clauses = clauses;
620 * mono_mb_set_param_names:
622 * PARAM_NAMES should have length equal to the sig->param_count, the caller retains
623 * ownership of the array, and its entries.
625 void
626 mono_mb_set_param_names (MonoMethodBuilder *mb, const char **param_names)
628 mb->param_names = param_names;