3 * Copyright 2018 Microsoft
4 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
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"
20 #include "class-init.h"
22 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
26 #include "mono/cil/opcode.def"
31 static MonoMethodBuilder
*
32 new_base_ilgen (MonoClass
*klass
, MonoWrapperType type
)
34 MonoMethodBuilder
*mb
;
37 g_assert (klass
!= NULL
);
39 mb
= g_new0 (MonoMethodBuilder
, 1);
41 mb
->method
= m
= (MonoMethod
*)g_new0 (MonoMethodWrapper
, 1);
45 m
->wrapper_type
= type
;
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
);
58 free_ilgen (MonoMethodBuilder
*mb
)
62 for (l
= mb
->locals_list
; l
; l
= l
->next
) {
63 /* Allocated in mono_mb_add_local () */
66 g_list_free (mb
->locals_list
);
77 create_method_ilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*signature
, int max_stack
)
79 MonoMethodHeader
*header
;
80 MonoMethodWrapper
*mw
;
86 g_assert (mb
!= NULL
);
88 image
= m_class_get_image (mb
->method
->klass
);
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
;
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
;
114 method
->name
= mb
->name
;
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
;
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
);
159 l
= g_list_reverse ((GList
*)mw
->method_data
);
160 if (method_is_dynamic (method
))
161 data
= (void **)g_malloc (sizeof (gpointer
) * (i
+ 1));
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
);
167 for (tmp
= l
; tmp
; tmp
= tmp
->next
) {
168 data
[i
++] = tmp
->data
;
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
));
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
);
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
);
218 mono_mb_add_local (MonoMethodBuilder
*mb
, MonoType
*type
)
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
);
233 mb
->locals_list
= g_list_append (mb
->locals_list
, t
);
240 * mono_mb_patch_addr:
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:
255 mono_mb_patch_addr_s (MonoMethodBuilder
*mb
, int pos
, gint8 value
)
257 *((gint8
*)(&mb
->code
[pos
])) = value
;
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:
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
);
284 mono_mb_emit_icon (mb
, offset
);
285 mono_mb_emit_byte (mb
, CEE_ADD
);
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
);
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);
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;
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:
344 mono_mb_emit_ldstr (MonoMethodBuilder
*mb
, char *str
)
346 mono_mb_emit_op (mb
, CEE_LDSTR
, str
);
350 * mono_mb_emit_ldarg:
353 mono_mb_emit_ldarg (MonoMethodBuilder
*mb
, guint argnum
)
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
);
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:
371 mono_mb_emit_ldarg_addr (MonoMethodBuilder
*mb
, guint argnum
)
374 mono_mb_emit_byte (mb
, CEE_LDARGA_S
);
375 mono_mb_emit_byte (mb
, argnum
);
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:
387 mono_mb_emit_ldloc_addr (MonoMethodBuilder
*mb
, guint locnum
)
390 mono_mb_emit_byte (mb
, CEE_LDLOCA_S
);
391 mono_mb_emit_byte (mb
, locnum
);
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:
403 mono_mb_emit_ldloc (MonoMethodBuilder
*mb
, guint num
)
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
);
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:
421 mono_mb_emit_stloc (MonoMethodBuilder
*mb
, guint num
)
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
);
429 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
430 mono_mb_emit_byte (mb
, CEE_STLOC
);
431 mono_mb_emit_i2 (mb
, num
);
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
);
447 mono_mb_emit_byte (mb
, CEE_LDC_I4
);
448 mono_mb_emit_i4 (mb
, value
);
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
)
466 mono_mb_get_pos (MonoMethodBuilder
*mb
)
472 * mono_mb_emit_branch:
475 mono_mb_emit_branch (MonoMethodBuilder
*mb
, guint8 op
)
478 mono_mb_emit_byte (mb
, op
);
480 mono_mb_emit_i4 (mb
, 0);
485 mono_mb_emit_short_branch (MonoMethodBuilder
*mb
, guint8 op
)
488 mono_mb_emit_byte (mb
, op
);
490 mono_mb_emit_byte (mb
, 0);
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));
503 mono_mb_patch_branch (MonoMethodBuilder
*mb
, guint32 pos
)
505 mono_mb_patch_addr (mb
, pos
, mb
->pos
- (pos
+ 4));
509 mono_mb_patch_short_branch (MonoMethodBuilder
*mb
, guint32 pos
)
511 mono_mb_patch_addr_s (mb
, pos
, mb
->pos
- (pos
+ 1));
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
);
522 mono_mb_emit_calli (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
)
524 mono_mb_emit_op (mb
, CEE_CALLI
, sig
);
528 * mono_mb_emit_managed_call:
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:
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
);
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
);
555 mono_mb_emit_exception_full (MonoMethodBuilder
*mb
, const char *exc_nspace
, const char *exc_name
, const char *msg
)
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
);
565 mono_mb_emit_op (mb
, CEE_NEWOBJ
, ctor
);
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:
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:
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:
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
);
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.
626 mono_mb_set_param_names (MonoMethodBuilder
*mb
, const char **param_names
)
628 mb
->param_names
= param_names
;