Merge pull request #3936 from kumpera/monoclass_reorg2
[mono-project.git] / mono / metadata / method-builder.c
blob09e6027f4a0d53b7f5c2d50eed49cc7c59b1479b
1 /*
2 * method-builder.c: Functions for creating IL methods at runtime.
3 *
4 * Author:
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.
12 #include "config.h"
13 #include "loader.h"
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"
22 #include <string.h>
23 #include <errno.h>
25 /* #define DEBUG_RUNTIME_CODE */
27 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
28 a = i,
30 enum {
31 #include "mono/cil/opcode.def"
32 LAST = 0xff
34 #undef OPDEF
36 #ifdef DEBUG_RUNTIME_CODE
37 static char*
38 indenter (MonoDisHelper *dh, MonoMethod *method, guint32 ip_offset)
40 return g_strdup (" ");
43 static MonoDisHelper marshal_dh = {
44 "\n",
45 "IL_%04x: ",
46 "IL_%04x",
47 indenter,
48 NULL,
49 NULL
51 #endif
53 static MonoMethodBuilder *
54 mono_mb_new_base (MonoClass *klass, MonoWrapperType type)
56 MonoMethodBuilder *mb;
57 MonoMethod *m;
59 g_assert (klass != NULL);
61 mb = g_new0 (MonoMethodBuilder, 1);
63 mb->method = m = (MonoMethod *)g_new0 (MonoMethodWrapper, 1);
65 m->klass = klass;
66 m->inline_info = 1;
67 m->wrapper_type = type;
69 #ifndef DISABLE_JIT
70 mb->code_size = 40;
71 mb->code = (unsigned char *)g_malloc (mb->code_size);
72 mb->init_locals = TRUE;
73 #endif
74 /* placeholder for the wrapper always at index 1 */
75 mono_mb_add_data (mb, NULL);
77 return mb;
80 MonoMethodBuilder *
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;
86 return mb;
89 MonoMethodBuilder *
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);
94 return mb;
97 void
98 mono_mb_free (MonoMethodBuilder *mb)
100 #ifndef DISABLE_JIT
101 GList *l;
103 for (l = mb->locals_list; l; l = l->next) {
104 /* Allocated in mono_mb_add_local () */
105 g_free (l->data);
107 g_list_free (mb->locals_list);
108 if (!mb->dynamic) {
109 g_free (mb->method);
110 if (!mb->no_dup_name)
111 g_free (mb->name);
112 g_free (mb->code);
114 #else
115 g_free (mb->method);
116 if (!mb->no_dup_name)
117 g_free (mb->name);
118 #endif
119 g_free (mb);
123 * mono_mb_create_method:
125 * Create a MonoMethod from this method builder.
126 * Returns: the newly created method.
129 MonoMethod *
130 mono_mb_create_method (MonoMethodBuilder *mb, MonoMethodSignature *signature, int max_stack)
132 #ifndef DISABLE_JIT
133 MonoMethodHeader *header;
134 #endif
135 MonoMethodWrapper *mw;
136 MonoImage *image;
137 MonoMethod *method;
138 GList *l;
139 int i;
141 g_assert (mb != NULL);
143 image = mb->method->klass->image;
145 #ifndef DISABLE_JIT
146 if (mb->dynamic) {
147 method = mb->method;
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;
161 } else
162 #endif
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;
170 if (mb->no_dup_name)
171 method->name = mb->name;
172 else
173 method->name = mono_image_strdup (image, mb->name);
175 #ifndef DISABLE_JIT
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;
185 #endif
188 #ifndef DISABLE_JIT
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;
192 #endif
194 method->signature = signature;
195 if (!signature->hasthis)
196 method->flags |= METHOD_ATTRIBUTE_STATIC;
198 #ifndef DISABLE_JIT
199 if (max_stack < 8)
200 max_stack = 8;
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;
212 #endif
214 i = g_list_length ((GList *)mw->method_data);
215 if (i) {
216 GList *tmp;
217 void **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));
221 else
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);
225 i = 1;
226 for (tmp = l; tmp; tmp = tmp->next) {
227 data [i++] = tmp->data;
229 g_list_free (l);
231 mw->method_data = data;
234 #ifndef DISABLE_JIT
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));
246 #endif
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);
259 #endif
261 return method;
264 guint32
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);
279 #ifndef DISABLE_JIT
282 mono_mb_add_local (MonoMethodBuilder *mb, MonoType *type)
284 int res;
285 MonoType *t;
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);
296 res = mb->locals;
297 mb->locals_list = g_list_append (mb->locals_list, t);
298 mb->locals++;
300 return res;
303 void
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;
312 void
313 mono_mb_patch_addr_s (MonoMethodBuilder *mb, int pos, gint8 value)
315 *((gint8 *)(&mb->code [pos])) = value;
318 void
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;
329 void
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);
335 if (offset) {
336 mono_mb_emit_icon (mb, offset);
337 mono_mb_emit_byte (mb, CEE_ADD);
341 void
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);
350 mb->pos += 4;
353 void
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);
363 mb->pos += 8;
366 void
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;
376 mb->pos += 2;
379 void
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));
386 void
387 mono_mb_emit_ldstr (MonoMethodBuilder *mb, char *str)
389 mono_mb_emit_op (mb, CEE_LDSTR, str);
392 void
393 mono_mb_emit_ldarg (MonoMethodBuilder *mb, guint argnum)
395 if (argnum < 4) {
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);
400 } else {
401 mono_mb_emit_byte (mb, CEE_PREFIX1);
402 mono_mb_emit_byte (mb, CEE_LDARG);
403 mono_mb_emit_i2 (mb, argnum);
407 void
408 mono_mb_emit_ldarg_addr (MonoMethodBuilder *mb, guint argnum)
410 if (argnum < 256) {
411 mono_mb_emit_byte (mb, CEE_LDARGA_S);
412 mono_mb_emit_byte (mb, argnum);
413 } else {
414 mono_mb_emit_byte (mb, CEE_PREFIX1);
415 mono_mb_emit_byte (mb, CEE_LDARGA);
416 mono_mb_emit_i2 (mb, argnum);
420 void
421 mono_mb_emit_ldloc_addr (MonoMethodBuilder *mb, guint locnum)
423 if (locnum < 256) {
424 mono_mb_emit_byte (mb, CEE_LDLOCA_S);
425 mono_mb_emit_byte (mb, locnum);
426 } else {
427 mono_mb_emit_byte (mb, CEE_PREFIX1);
428 mono_mb_emit_byte (mb, CEE_LDLOCA);
429 mono_mb_emit_i2 (mb, locnum);
433 void
434 mono_mb_emit_ldloc (MonoMethodBuilder *mb, guint num)
436 if (num < 4) {
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);
441 } else {
442 mono_mb_emit_byte (mb, CEE_PREFIX1);
443 mono_mb_emit_byte (mb, CEE_LDLOC);
444 mono_mb_emit_i2 (mb, num);
448 void
449 mono_mb_emit_stloc (MonoMethodBuilder *mb, guint num)
451 if (num < 4) {
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);
456 } else {
457 mono_mb_emit_byte (mb, CEE_PREFIX1);
458 mono_mb_emit_byte (mb, CEE_STLOC);
459 mono_mb_emit_i2 (mb, num);
463 void
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);
471 } else {
472 mono_mb_emit_byte (mb, CEE_LDC_I4);
473 mono_mb_emit_i4 (mb, value);
477 void
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)
487 return mb->pos;
491 mono_mb_get_pos (MonoMethodBuilder *mb)
493 return mb->pos;
496 guint32
497 mono_mb_emit_branch (MonoMethodBuilder *mb, guint8 op)
499 guint32 res;
500 mono_mb_emit_byte (mb, op);
501 res = mb->pos;
502 mono_mb_emit_i4 (mb, 0);
503 return res;
506 guint32
507 mono_mb_emit_short_branch (MonoMethodBuilder *mb, guint8 op)
509 guint32 res;
510 mono_mb_emit_byte (mb, op);
511 res = mb->pos;
512 mono_mb_emit_byte (mb, 0);
514 return res;
517 void
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));
524 void
525 mono_mb_patch_branch (MonoMethodBuilder *mb, guint32 pos)
527 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
530 void
531 mono_mb_patch_short_branch (MonoMethodBuilder *mb, guint32 pos)
533 mono_mb_patch_addr_s (mb, pos, mb->pos - (pos + 1));
536 void
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);
543 void
544 mono_mb_emit_calli (MonoMethodBuilder *mb, MonoMethodSignature *sig)
546 mono_mb_emit_op (mb, CEE_CALLI, sig);
549 void
550 mono_mb_emit_managed_call (MonoMethodBuilder *mb, MonoMethod *method, MonoMethodSignature *opt_sig)
552 mono_mb_emit_op (mb, CEE_CALL, method);
555 void
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);
562 void
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);
569 void
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);
577 g_assert (ctor);
578 mono_mb_emit_op (mb, CEE_NEWOBJ, ctor);
579 if (msg != NULL) {
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);
588 void
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);
594 void
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);
603 void
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.
616 void
617 mono_mb_set_param_names (MonoMethodBuilder *mb, const char **param_names)
619 mb->param_names = param_names;
622 #endif /* DISABLE_JIT */