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)
13 #include "mono/metadata/method-builder.h"
14 #include "mono/metadata/tabledefs.h"
15 #include "mono/metadata/exception.h"
16 #include "mono/metadata/appdomain.h"
17 #include "mono/metadata/debug-helpers.h"
18 #include "mono/metadata/metadata-internals.h"
19 #include "mono/metadata/domain-internals.h"
23 /* #define DEBUG_RUNTIME_CODE */
25 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
29 #include "mono/cil/opcode.def"
34 #ifdef DEBUG_RUNTIME_CODE
36 indenter (MonoDisHelper
*dh
, MonoMethod
*method
, guint32 ip_offset
)
38 return g_strdup (" ");
41 static MonoDisHelper marshal_dh
= {
51 static MonoMethodBuilder
*
52 mono_mb_new_base (MonoClass
*klass
, MonoWrapperType type
)
54 MonoMethodBuilder
*mb
;
57 g_assert (klass
!= NULL
);
59 mb
= g_new0 (MonoMethodBuilder
, 1);
61 mb
->method
= m
= (MonoMethod
*)g_new0 (MonoMethodWrapper
, 1);
65 m
->wrapper_type
= type
;
68 mb
->code
= g_malloc (mb
->code_size
);
69 /* placeholder for the wrapper always at index 1 */
70 mono_mb_add_data (mb
, NULL
);
76 mono_mb_new_no_dup_name (MonoClass
*klass
, const char *name
, MonoWrapperType type
)
78 MonoMethodBuilder
*mb
= mono_mb_new_base (klass
, type
);
79 mb
->name
= (char*)name
;
80 mb
->no_dup_name
= TRUE
;
85 mono_mb_new (MonoClass
*klass
, const char *name
, MonoWrapperType type
)
87 MonoMethodBuilder
*mb
= mono_mb_new_base (klass
, type
);
88 mb
->name
= g_strdup (name
);
93 mono_mb_free (MonoMethodBuilder
*mb
)
95 g_list_free (mb
->locals_list
);
106 mono_mb_add_local (MonoMethodBuilder
*mb
, MonoType
*type
)
110 g_assert (mb
!= NULL
);
111 g_assert (type
!= NULL
);
114 mb
->locals_list
= g_list_append (mb
->locals_list
, type
);
121 * mono_mb_create_method:
123 * Create a MonoMethod from this method builder.
124 * Returns: the newly created method.
126 * LOCKING: Takes the loader lock.
129 mono_mb_create_method (MonoMethodBuilder
*mb
, MonoMethodSignature
*signature
, int max_stack
)
131 MonoMethodHeader
*header
;
132 MonoMethodWrapper
*mw
;
138 g_assert (mb
!= NULL
);
140 image
= mb
->method
->klass
->image
;
142 mono_loader_lock (); /*FIXME I think this lock can go.*/
145 mw
= (MonoMethodWrapper
*)method
;
147 method
->name
= mb
->name
;
148 method
->dynamic
= TRUE
;
150 mw
->header
= header
= (MonoMethodHeader
*)
151 g_malloc0 (MONO_SIZEOF_METHOD_HEADER
+ mb
->locals
* sizeof (MonoType
*));
153 header
->code
= mb
->code
;
155 for (i
= 0, l
= mb
->locals_list
; l
; l
= l
->next
, i
++) {
156 header
->locals
[i
] = mono_metadata_type_dup (NULL
, (MonoType
*)l
->data
);
159 /* Realloc the method info into a mempool */
161 method
= mono_image_alloc0 (image
, sizeof (MonoMethodWrapper
));
162 memcpy (method
, mb
->method
, sizeof (MonoMethodWrapper
));
163 mw
= (MonoMethodWrapper
*) method
;
166 method
->name
= mb
->name
;
168 method
->name
= mono_image_strdup (image
, mb
->name
);
170 mw
->header
= header
= (MonoMethodHeader
*)
171 mono_image_alloc0 (image
, MONO_SIZEOF_METHOD_HEADER
+ mb
->locals
* sizeof (MonoType
*));
173 header
->code
= mono_image_alloc (image
, mb
->pos
);
174 memcpy ((char*)header
->code
, mb
->code
, mb
->pos
);
176 for (i
= 0, l
= mb
->locals_list
; l
; l
= l
->next
, i
++) {
177 header
->locals
[i
] = (MonoType
*)l
->data
;
184 header
->max_stack
= max_stack
;
186 method
->signature
= signature
;
188 header
->code_size
= mb
->pos
;
189 header
->num_locals
= mb
->locals
;
190 header
->init_locals
= TRUE
;
192 header
->num_clauses
= mb
->num_clauses
;
193 header
->clauses
= mb
->clauses
;
195 method
->skip_visibility
= mb
->skip_visibility
;
197 i
= g_list_length (mw
->method_data
);
201 l
= g_list_reverse (mw
->method_data
);
203 data
= g_malloc (sizeof (gpointer
) * (i
+ 1));
205 data
= mono_image_alloc (image
, sizeof (gpointer
) * (i
+ 1));
206 /* store the size in the first element */
207 data
[0] = GUINT_TO_POINTER (i
);
209 for (tmp
= l
; tmp
; tmp
= tmp
->next
) {
210 data
[i
++] = tmp
->data
;
214 mw
->method_data
= data
;
217 static int total_code = 0;
218 static int total_alloc = 0;
219 total_code += mb->pos;
220 total_alloc += mb->code_size;
221 g_print ("code size: %d of %d (allocated: %d)\n", mb->pos, total_code, total_alloc);
224 #ifdef DEBUG_RUNTIME_CODE
225 printf ("RUNTIME CODE FOR %s\n", mono_method_full_name (method
, TRUE
));
226 printf ("%s\n", mono_disasm_code (&marshal_dh
, method
, mb
->code
, mb
->code
+ mb
->pos
));
229 mono_loader_unlock ();
234 mono_mb_add_data (MonoMethodBuilder
*mb
, gpointer data
)
236 MonoMethodWrapper
*mw
;
238 g_assert (mb
!= NULL
);
240 mw
= (MonoMethodWrapper
*)mb
->method
;
242 /* one O(n) is enough */
243 mw
->method_data
= g_list_prepend (mw
->method_data
, data
);
245 return g_list_length (mw
->method_data
);
249 mono_mb_patch_addr (MonoMethodBuilder
*mb
, int pos
, int value
)
251 mb
->code
[pos
] = value
& 0xff;
252 mb
->code
[pos
+ 1] = (value
>> 8) & 0xff;
253 mb
->code
[pos
+ 2] = (value
>> 16) & 0xff;
254 mb
->code
[pos
+ 3] = (value
>> 24) & 0xff;
258 mono_mb_patch_addr_s (MonoMethodBuilder
*mb
, int pos
, gint8 value
)
260 *((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
= g_realloc (mb
->code
, mb
->code_size
);
271 mb
->code
[mb
->pos
++] = op
;
275 mono_mb_emit_ldflda (MonoMethodBuilder
*mb
, gint32 offset
)
277 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
278 mono_mb_emit_byte (mb
, CEE_MONO_OBJADDR
);
281 mono_mb_emit_icon (mb
, offset
);
282 mono_mb_emit_byte (mb
, CEE_ADD
);
287 mono_mb_emit_i4 (MonoMethodBuilder
*mb
, gint32 data
)
289 if ((mb
->pos
+ 4) >= mb
->code_size
) {
290 mb
->code_size
+= mb
->code_size
>> 1;
291 mb
->code
= g_realloc (mb
->code
, mb
->code_size
);
294 mono_mb_patch_addr (mb
, mb
->pos
, data
);
299 mono_mb_emit_i2 (MonoMethodBuilder
*mb
, gint16 data
)
301 if ((mb
->pos
+ 2) >= mb
->code_size
) {
302 mb
->code_size
+= mb
->code_size
>> 1;
303 mb
->code
= g_realloc (mb
->code
, mb
->code_size
);
306 mb
->code
[mb
->pos
] = data
& 0xff;
307 mb
->code
[mb
->pos
+ 1] = (data
>> 8) & 0xff;
312 mono_mb_emit_op (MonoMethodBuilder
*mb
, guint8 op
, gpointer data
)
314 mono_mb_emit_byte (mb
, op
);
315 mono_mb_emit_i4 (mb
, mono_mb_add_data (mb
, data
));
319 mono_mb_emit_ldstr (MonoMethodBuilder
*mb
, char *str
)
321 mono_mb_emit_op (mb
, CEE_LDSTR
, str
);
325 mono_mb_emit_ldarg (MonoMethodBuilder
*mb
, guint argnum
)
328 mono_mb_emit_byte (mb
, CEE_LDARG_0
+ argnum
);
329 } else if (argnum
< 256) {
330 mono_mb_emit_byte (mb
, CEE_LDARG_S
);
331 mono_mb_emit_byte (mb
, argnum
);
333 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
334 mono_mb_emit_byte (mb
, CEE_LDARG
);
335 mono_mb_emit_i2 (mb
, argnum
);
340 mono_mb_emit_ldarg_addr (MonoMethodBuilder
*mb
, guint argnum
)
343 mono_mb_emit_byte (mb
, CEE_LDARGA_S
);
344 mono_mb_emit_byte (mb
, argnum
);
346 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
347 mono_mb_emit_byte (mb
, CEE_LDARGA
);
348 mono_mb_emit_i2 (mb
, argnum
);
353 mono_mb_emit_ldloc_addr (MonoMethodBuilder
*mb
, guint locnum
)
356 mono_mb_emit_byte (mb
, CEE_LDLOCA_S
);
357 mono_mb_emit_byte (mb
, locnum
);
359 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
360 mono_mb_emit_byte (mb
, CEE_LDLOCA
);
361 mono_mb_emit_i2 (mb
, locnum
);
366 mono_mb_emit_ldloc (MonoMethodBuilder
*mb
, guint num
)
369 mono_mb_emit_byte (mb
, CEE_LDLOC_0
+ num
);
370 } else if (num
< 256) {
371 mono_mb_emit_byte (mb
, CEE_LDLOC_S
);
372 mono_mb_emit_byte (mb
, num
);
374 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
375 mono_mb_emit_byte (mb
, CEE_LDLOC
);
376 mono_mb_emit_i2 (mb
, num
);
381 mono_mb_emit_stloc (MonoMethodBuilder
*mb
, guint num
)
384 mono_mb_emit_byte (mb
, CEE_STLOC_0
+ num
);
385 } else if (num
< 256) {
386 mono_mb_emit_byte (mb
, CEE_STLOC_S
);
387 mono_mb_emit_byte (mb
, num
);
389 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
390 mono_mb_emit_byte (mb
, CEE_STLOC
);
391 mono_mb_emit_i2 (mb
, num
);
396 mono_mb_emit_icon (MonoMethodBuilder
*mb
, gint32 value
)
398 if (value
>= -1 && value
< 8) {
399 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
+ value
);
400 } else if (value
>= -128 && value
<= 127) {
401 mono_mb_emit_byte (mb
, CEE_LDC_I4_S
);
402 mono_mb_emit_byte (mb
, value
);
404 mono_mb_emit_byte (mb
, CEE_LDC_I4
);
405 mono_mb_emit_i4 (mb
, value
);
410 mono_mb_get_label (MonoMethodBuilder
*mb
)
416 mono_mb_get_pos (MonoMethodBuilder
*mb
)
422 mono_mb_emit_branch (MonoMethodBuilder
*mb
, guint8 op
)
425 mono_mb_emit_byte (mb
, op
);
427 mono_mb_emit_i4 (mb
, 0);
432 mono_mb_emit_short_branch (MonoMethodBuilder
*mb
, guint8 op
)
435 mono_mb_emit_byte (mb
, op
);
437 mono_mb_emit_byte (mb
, 0);
443 mono_mb_emit_branch_label (MonoMethodBuilder
*mb
, guint8 op
, guint32 label
)
445 mono_mb_emit_byte (mb
, op
);
446 mono_mb_emit_i4 (mb
, label
- (mb
->pos
+ 4));
450 mono_mb_patch_branch (MonoMethodBuilder
*mb
, guint32 pos
)
452 mono_mb_patch_addr (mb
, pos
, mb
->pos
- (pos
+ 4));
456 mono_mb_patch_short_branch (MonoMethodBuilder
*mb
, guint32 pos
)
458 mono_mb_patch_addr_s (mb
, pos
, mb
->pos
- (pos
+ 1));
462 mono_mb_emit_ptr (MonoMethodBuilder
*mb
, gpointer ptr
)
464 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
465 mono_mb_emit_op (mb
, CEE_MONO_LDPTR
, ptr
);
469 mono_mb_emit_calli (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
)
471 mono_mb_emit_op (mb
, CEE_CALLI
, sig
);
475 mono_mb_emit_managed_call (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*opt_sig
)
477 mono_mb_emit_op (mb
, CEE_CALL
, method
);
481 mono_mb_emit_native_call (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
, gpointer func
)
483 mono_mb_emit_ptr (mb
, func
);
484 mono_mb_emit_calli (mb
, sig
);
488 mono_mb_emit_icall (MonoMethodBuilder
*mb
, gpointer func
)
490 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
491 mono_mb_emit_op (mb
, CEE_MONO_ICALL
, func
);
495 mono_mb_emit_exception_full (MonoMethodBuilder
*mb
, const char *exc_nspace
, const char *exc_name
, const char *msg
)
497 MonoMethod
*ctor
= NULL
;
499 MonoClass
*mme
= mono_class_from_name (mono_defaults
.corlib
, exc_nspace
, exc_name
);
500 mono_class_init (mme
);
501 ctor
= mono_class_get_method_from_name (mme
, ".ctor", 0);
503 mono_mb_emit_op (mb
, CEE_NEWOBJ
, ctor
);
505 mono_mb_emit_byte (mb
, CEE_DUP
);
506 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoException
, message
));
507 mono_mb_emit_ldstr (mb
, (char*)msg
);
508 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
510 mono_mb_emit_byte (mb
, CEE_THROW
);
514 mono_mb_emit_exception (MonoMethodBuilder
*mb
, const char *exc_name
, const char *msg
)
516 mono_mb_emit_exception_full (mb
, "System", exc_name
, msg
);
520 mono_mb_emit_add_to_local (MonoMethodBuilder
*mb
, guint16 local
, gint32 incr
)
522 mono_mb_emit_ldloc (mb
, local
);
523 mono_mb_emit_icon (mb
, incr
);
524 mono_mb_emit_byte (mb
, CEE_ADD
);
525 mono_mb_emit_stloc (mb
, local
);
529 mono_mb_set_clauses (MonoMethodBuilder
*mb
, int num_clauses
, MonoExceptionClause
*clauses
)
531 mb
->num_clauses
= num_clauses
;
532 mb
->clauses
= clauses
;