2 * method-builder.c: Functions for creating IL methods at runtime.
5 * Paolo Molaro (lupus@ximian.com)
7 * Copyright 2002-2003 Ximian, Inc (http://www.ximian.com)
8 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
9 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14 #include "mono/metadata/abi-details.h"
15 #include "mono/metadata/method-builder.h"
16 #include "mono/metadata/tabledefs.h"
17 #include "mono/metadata/exception.h"
18 #include "mono/metadata/appdomain.h"
19 #include "mono/metadata/debug-helpers.h"
20 #include "mono/metadata/metadata-internals.h"
21 #include "mono/metadata/domain-internals.h"
25 /* #define DEBUG_RUNTIME_CODE */
27 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
31 #include "mono/cil/opcode.def"
36 #ifdef DEBUG_RUNTIME_CODE
38 indenter (MonoDisHelper
*dh
, MonoMethod
*method
, guint32 ip_offset
)
40 return g_strdup (" ");
43 static MonoDisHelper marshal_dh
= {
53 static MonoMethodBuilder
*
54 mono_mb_new_base (MonoClass
*klass
, MonoWrapperType type
)
56 MonoMethodBuilder
*mb
;
59 g_assert (klass
!= NULL
);
61 mb
= g_new0 (MonoMethodBuilder
, 1);
63 mb
->method
= m
= (MonoMethod
*)g_new0 (MonoMethodWrapper
, 1);
67 m
->wrapper_type
= type
;
71 mb
->code
= (unsigned char *)g_malloc (mb
->code_size
);
72 mb
->init_locals
= TRUE
;
74 /* placeholder for the wrapper always at index 1 */
75 mono_mb_add_data (mb
, NULL
);
81 mono_mb_new_no_dup_name (MonoClass
*klass
, const char *name
, MonoWrapperType type
)
83 MonoMethodBuilder
*mb
= mono_mb_new_base (klass
, type
);
84 mb
->name
= (char*)name
;
85 mb
->no_dup_name
= TRUE
;
90 mono_mb_new (MonoClass
*klass
, const char *name
, MonoWrapperType type
)
92 MonoMethodBuilder
*mb
= mono_mb_new_base (klass
, type
);
93 mb
->name
= g_strdup (name
);
98 mono_mb_free (MonoMethodBuilder
*mb
)
103 for (l
= mb
->locals_list
; l
; l
= l
->next
) {
104 /* Allocated in mono_mb_add_local () */
107 g_list_free (mb
->locals_list
);
110 if (!mb
->no_dup_name
)
116 if (!mb
->no_dup_name
)
123 * mono_mb_create_method:
125 * Create a MonoMethod from this method builder.
126 * Returns: the newly created method.
130 mono_mb_create_method (MonoMethodBuilder
*mb
, MonoMethodSignature
*signature
, int max_stack
)
133 MonoMethodHeader
*header
;
135 MonoMethodWrapper
*mw
;
141 g_assert (mb
!= NULL
);
143 image
= mb
->method
->klass
->image
;
148 mw
= (MonoMethodWrapper
*)method
;
150 method
->name
= mb
->name
;
151 method
->dynamic
= TRUE
;
153 mw
->header
= header
= (MonoMethodHeader
*)
154 g_malloc0 (MONO_SIZEOF_METHOD_HEADER
+ mb
->locals
* sizeof (MonoType
*));
156 header
->code
= mb
->code
;
158 for (i
= 0, l
= mb
->locals_list
; l
; l
= l
->next
, i
++) {
159 header
->locals
[i
] = (MonoType
*)l
->data
;
164 /* Realloc the method info into a mempool */
166 method
= (MonoMethod
*)mono_image_alloc0 (image
, sizeof (MonoMethodWrapper
));
167 memcpy (method
, mb
->method
, sizeof (MonoMethodWrapper
));
168 mw
= (MonoMethodWrapper
*) method
;
171 method
->name
= mb
->name
;
173 method
->name
= mono_image_strdup (image
, mb
->name
);
176 mw
->header
= header
= (MonoMethodHeader
*)
177 mono_image_alloc0 (image
, MONO_SIZEOF_METHOD_HEADER
+ mb
->locals
* sizeof (MonoType
*));
179 header
->code
= (const unsigned char *)mono_image_alloc (image
, mb
->pos
);
180 memcpy ((char*)header
->code
, mb
->code
, mb
->pos
);
182 for (i
= 0, l
= mb
->locals_list
; l
; l
= l
->next
, i
++) {
183 header
->locals
[i
] = (MonoType
*)l
->data
;
189 /* Free the locals list so mono_mb_free () doesn't free the types twice */
190 g_list_free (mb
->locals_list
);
191 mb
->locals_list
= NULL
;
194 method
->signature
= signature
;
195 if (!signature
->hasthis
)
196 method
->flags
|= METHOD_ATTRIBUTE_STATIC
;
202 header
->max_stack
= max_stack
;
204 header
->code_size
= mb
->pos
;
205 header
->num_locals
= mb
->locals
;
206 header
->init_locals
= mb
->init_locals
;
208 header
->num_clauses
= mb
->num_clauses
;
209 header
->clauses
= mb
->clauses
;
211 method
->skip_visibility
= mb
->skip_visibility
;
214 i
= g_list_length ((GList
*)mw
->method_data
);
218 l
= g_list_reverse ((GList
*)mw
->method_data
);
219 if (method_is_dynamic (method
))
220 data
= (void **)g_malloc (sizeof (gpointer
) * (i
+ 1));
222 data
= (void **)mono_image_alloc (image
, sizeof (gpointer
) * (i
+ 1));
223 /* store the size in the first element */
224 data
[0] = GUINT_TO_POINTER (i
);
226 for (tmp
= l
; tmp
; tmp
= tmp
->next
) {
227 data
[i
++] = tmp
->data
;
231 mw
->method_data
= data
;
236 static int total_code = 0;
237 static int total_alloc = 0;
238 total_code += mb->pos;
239 total_alloc += mb->code_size;
240 g_print ("code size: %d of %d (allocated: %d)\n", mb->pos, total_code, total_alloc);
243 #ifdef DEBUG_RUNTIME_CODE
244 printf ("RUNTIME CODE FOR %s\n", mono_method_full_name (method
, TRUE
));
245 printf ("%s\n", mono_disasm_code (&marshal_dh
, method
, mb
->code
, mb
->code
+ mb
->pos
));
248 if (mb
->param_names
) {
249 char **param_names
= (char **)mono_image_alloc0 (image
, signature
->param_count
* sizeof (gpointer
));
250 for (i
= 0; i
< signature
->param_count
; ++i
)
251 param_names
[i
] = mono_image_strdup (image
, mb
->param_names
[i
]);
253 mono_image_lock (image
);
254 if (!image
->wrapper_param_names
)
255 image
->wrapper_param_names
= g_hash_table_new (NULL
, NULL
);
256 g_hash_table_insert (image
->wrapper_param_names
, method
, param_names
);
257 mono_image_unlock (image
);
265 mono_mb_add_data (MonoMethodBuilder
*mb
, gpointer data
)
267 MonoMethodWrapper
*mw
;
269 g_assert (mb
!= NULL
);
271 mw
= (MonoMethodWrapper
*)mb
->method
;
273 /* one O(n) is enough */
274 mw
->method_data
= g_list_prepend ((GList
*)mw
->method_data
, data
);
276 return g_list_length ((GList
*)mw
->method_data
);
282 mono_mb_add_local (MonoMethodBuilder
*mb
, MonoType
*type
)
288 * Have to make a copy early since type might be sig->ret,
289 * which is transient, see mono_metadata_signature_dup_internal_with_padding ().
291 t
= mono_metadata_type_dup (NULL
, type
);
293 g_assert (mb
!= NULL
);
294 g_assert (type
!= NULL
);
297 mb
->locals_list
= g_list_append (mb
->locals_list
, t
);
304 mono_mb_patch_addr (MonoMethodBuilder
*mb
, int pos
, int value
)
306 mb
->code
[pos
] = value
& 0xff;
307 mb
->code
[pos
+ 1] = (value
>> 8) & 0xff;
308 mb
->code
[pos
+ 2] = (value
>> 16) & 0xff;
309 mb
->code
[pos
+ 3] = (value
>> 24) & 0xff;
313 mono_mb_patch_addr_s (MonoMethodBuilder
*mb
, int pos
, gint8 value
)
315 *((gint8
*)(&mb
->code
[pos
])) = value
;
319 mono_mb_emit_byte (MonoMethodBuilder
*mb
, guint8 op
)
321 if (mb
->pos
>= mb
->code_size
) {
322 mb
->code_size
+= mb
->code_size
>> 1;
323 mb
->code
= (unsigned char *)g_realloc (mb
->code
, mb
->code_size
);
326 mb
->code
[mb
->pos
++] = op
;
330 mono_mb_emit_ldflda (MonoMethodBuilder
*mb
, gint32 offset
)
332 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
333 mono_mb_emit_byte (mb
, CEE_MONO_OBJADDR
);
336 mono_mb_emit_icon (mb
, offset
);
337 mono_mb_emit_byte (mb
, CEE_ADD
);
342 mono_mb_emit_i4 (MonoMethodBuilder
*mb
, gint32 data
)
344 if ((mb
->pos
+ 4) >= mb
->code_size
) {
345 mb
->code_size
+= mb
->code_size
>> 1;
346 mb
->code
= (unsigned char *)g_realloc (mb
->code
, mb
->code_size
);
349 mono_mb_patch_addr (mb
, mb
->pos
, data
);
354 mono_mb_emit_i8 (MonoMethodBuilder
*mb
, gint64 data
)
356 if ((mb
->pos
+ 8) >= mb
->code_size
) {
357 mb
->code_size
+= mb
->code_size
>> 1;
358 mb
->code
= (unsigned char *)g_realloc (mb
->code
, mb
->code_size
);
361 mono_mb_patch_addr (mb
, mb
->pos
, data
);
362 mono_mb_patch_addr (mb
, mb
->pos
+ 4, data
>> 32);
367 mono_mb_emit_i2 (MonoMethodBuilder
*mb
, gint16 data
)
369 if ((mb
->pos
+ 2) >= mb
->code_size
) {
370 mb
->code_size
+= mb
->code_size
>> 1;
371 mb
->code
= (unsigned char *)g_realloc (mb
->code
, mb
->code_size
);
374 mb
->code
[mb
->pos
] = data
& 0xff;
375 mb
->code
[mb
->pos
+ 1] = (data
>> 8) & 0xff;
380 mono_mb_emit_op (MonoMethodBuilder
*mb
, guint8 op
, gpointer data
)
382 mono_mb_emit_byte (mb
, op
);
383 mono_mb_emit_i4 (mb
, mono_mb_add_data (mb
, data
));
387 mono_mb_emit_ldstr (MonoMethodBuilder
*mb
, char *str
)
389 mono_mb_emit_op (mb
, CEE_LDSTR
, str
);
393 mono_mb_emit_ldarg (MonoMethodBuilder
*mb
, guint argnum
)
396 mono_mb_emit_byte (mb
, CEE_LDARG_0
+ argnum
);
397 } else if (argnum
< 256) {
398 mono_mb_emit_byte (mb
, CEE_LDARG_S
);
399 mono_mb_emit_byte (mb
, argnum
);
401 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
402 mono_mb_emit_byte (mb
, CEE_LDARG
);
403 mono_mb_emit_i2 (mb
, argnum
);
408 mono_mb_emit_ldarg_addr (MonoMethodBuilder
*mb
, guint argnum
)
411 mono_mb_emit_byte (mb
, CEE_LDARGA_S
);
412 mono_mb_emit_byte (mb
, argnum
);
414 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
415 mono_mb_emit_byte (mb
, CEE_LDARGA
);
416 mono_mb_emit_i2 (mb
, argnum
);
421 mono_mb_emit_ldloc_addr (MonoMethodBuilder
*mb
, guint locnum
)
424 mono_mb_emit_byte (mb
, CEE_LDLOCA_S
);
425 mono_mb_emit_byte (mb
, locnum
);
427 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
428 mono_mb_emit_byte (mb
, CEE_LDLOCA
);
429 mono_mb_emit_i2 (mb
, locnum
);
434 mono_mb_emit_ldloc (MonoMethodBuilder
*mb
, guint num
)
437 mono_mb_emit_byte (mb
, CEE_LDLOC_0
+ num
);
438 } else if (num
< 256) {
439 mono_mb_emit_byte (mb
, CEE_LDLOC_S
);
440 mono_mb_emit_byte (mb
, num
);
442 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
443 mono_mb_emit_byte (mb
, CEE_LDLOC
);
444 mono_mb_emit_i2 (mb
, num
);
449 mono_mb_emit_stloc (MonoMethodBuilder
*mb
, guint num
)
452 mono_mb_emit_byte (mb
, CEE_STLOC_0
+ num
);
453 } else if (num
< 256) {
454 mono_mb_emit_byte (mb
, CEE_STLOC_S
);
455 mono_mb_emit_byte (mb
, num
);
457 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
458 mono_mb_emit_byte (mb
, CEE_STLOC
);
459 mono_mb_emit_i2 (mb
, num
);
464 mono_mb_emit_icon (MonoMethodBuilder
*mb
, gint32 value
)
466 if (value
>= -1 && value
< 8) {
467 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
+ value
);
468 } else if (value
>= -128 && value
<= 127) {
469 mono_mb_emit_byte (mb
, CEE_LDC_I4_S
);
470 mono_mb_emit_byte (mb
, value
);
472 mono_mb_emit_byte (mb
, CEE_LDC_I4
);
473 mono_mb_emit_i4 (mb
, value
);
478 mono_mb_emit_icon8 (MonoMethodBuilder
*mb
, gint64 value
)
480 mono_mb_emit_byte (mb
, CEE_LDC_I8
);
481 mono_mb_emit_i8 (mb
, value
);
485 mono_mb_get_label (MonoMethodBuilder
*mb
)
491 mono_mb_get_pos (MonoMethodBuilder
*mb
)
497 mono_mb_emit_branch (MonoMethodBuilder
*mb
, guint8 op
)
500 mono_mb_emit_byte (mb
, op
);
502 mono_mb_emit_i4 (mb
, 0);
507 mono_mb_emit_short_branch (MonoMethodBuilder
*mb
, guint8 op
)
510 mono_mb_emit_byte (mb
, op
);
512 mono_mb_emit_byte (mb
, 0);
518 mono_mb_emit_branch_label (MonoMethodBuilder
*mb
, guint8 op
, guint32 label
)
520 mono_mb_emit_byte (mb
, op
);
521 mono_mb_emit_i4 (mb
, label
- (mb
->pos
+ 4));
525 mono_mb_patch_branch (MonoMethodBuilder
*mb
, guint32 pos
)
527 mono_mb_patch_addr (mb
, pos
, mb
->pos
- (pos
+ 4));
531 mono_mb_patch_short_branch (MonoMethodBuilder
*mb
, guint32 pos
)
533 mono_mb_patch_addr_s (mb
, pos
, mb
->pos
- (pos
+ 1));
537 mono_mb_emit_ptr (MonoMethodBuilder
*mb
, gpointer ptr
)
539 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
540 mono_mb_emit_op (mb
, CEE_MONO_LDPTR
, ptr
);
544 mono_mb_emit_calli (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
)
546 mono_mb_emit_op (mb
, CEE_CALLI
, sig
);
550 mono_mb_emit_managed_call (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*opt_sig
)
552 mono_mb_emit_op (mb
, CEE_CALL
, method
);
556 mono_mb_emit_native_call (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
, gpointer func
)
558 mono_mb_emit_ptr (mb
, func
);
559 mono_mb_emit_calli (mb
, sig
);
563 mono_mb_emit_icall (MonoMethodBuilder
*mb
, gpointer func
)
565 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
566 mono_mb_emit_op (mb
, CEE_MONO_ICALL
, func
);
570 mono_mb_emit_exception_full (MonoMethodBuilder
*mb
, const char *exc_nspace
, const char *exc_name
, const char *msg
)
572 MonoMethod
*ctor
= NULL
;
574 MonoClass
*mme
= mono_class_load_from_name (mono_defaults
.corlib
, exc_nspace
, exc_name
);
575 mono_class_init (mme
);
576 ctor
= mono_class_get_method_from_name (mme
, ".ctor", 0);
578 mono_mb_emit_op (mb
, CEE_NEWOBJ
, ctor
);
580 mono_mb_emit_byte (mb
, CEE_DUP
);
581 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoException
, message
));
582 mono_mb_emit_ldstr (mb
, (char*)msg
);
583 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
585 mono_mb_emit_byte (mb
, CEE_THROW
);
589 mono_mb_emit_exception (MonoMethodBuilder
*mb
, const char *exc_name
, const char *msg
)
591 mono_mb_emit_exception_full (mb
, "System", exc_name
, msg
);
595 mono_mb_emit_add_to_local (MonoMethodBuilder
*mb
, guint16 local
, gint32 incr
)
597 mono_mb_emit_ldloc (mb
, local
);
598 mono_mb_emit_icon (mb
, incr
);
599 mono_mb_emit_byte (mb
, CEE_ADD
);
600 mono_mb_emit_stloc (mb
, local
);
604 mono_mb_set_clauses (MonoMethodBuilder
*mb
, int num_clauses
, MonoExceptionClause
*clauses
)
606 mb
->num_clauses
= num_clauses
;
607 mb
->clauses
= clauses
;
611 * mono_mb_set_param_names:
613 * PARAM_NAMES should have length equal to the sig->param_count, the caller retains
614 * ownership of the array, and its entries.
617 mono_mb_set_param_names (MonoMethodBuilder
*mb
, const char **param_names
)
619 mb
->param_names
= param_names
;
622 #endif /* DISABLE_JIT */