Bump version to 2.7.1
[mono-project/dkf.git] / mono / metadata / method-builder.c
blob247c749bdedad87bad1932fc978dea8bb7f81eb9
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 */
11 #include "config.h"
12 #include "loader.h"
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"
20 #include <string.h>
21 #include <errno.h>
23 /* #define DEBUG_RUNTIME_CODE */
25 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
26 a = i,
28 enum {
29 #include "mono/cil/opcode.def"
30 LAST = 0xff
32 #undef OPDEF
34 #ifdef DEBUG_RUNTIME_CODE
35 static char*
36 indenter (MonoDisHelper *dh, MonoMethod *method, guint32 ip_offset)
38 return g_strdup (" ");
41 static MonoDisHelper marshal_dh = {
42 "\n",
43 "IL_%04x: ",
44 "IL_%04x",
45 indenter,
46 NULL,
47 NULL
49 #endif
51 static MonoMethodBuilder *
52 mono_mb_new_base (MonoClass *klass, MonoWrapperType type)
54 MonoMethodBuilder *mb;
55 MonoMethod *m;
57 g_assert (klass != NULL);
59 mb = g_new0 (MonoMethodBuilder, 1);
61 mb->method = m = (MonoMethod *)g_new0 (MonoMethodWrapper, 1);
63 m->klass = klass;
64 m->inline_info = 1;
65 m->wrapper_type = type;
67 mb->code_size = 40;
68 mb->code = g_malloc (mb->code_size);
69 /* placeholder for the wrapper always at index 1 */
70 mono_mb_add_data (mb, NULL);
72 return mb;
75 MonoMethodBuilder *
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;
81 return mb;
84 MonoMethodBuilder *
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);
89 return mb;
92 void
93 mono_mb_free (MonoMethodBuilder *mb)
95 g_list_free (mb->locals_list);
96 if (!mb->dynamic) {
97 g_free (mb->method);
98 if (!mb->no_dup_name)
99 g_free (mb->name);
100 g_free (mb->code);
102 g_free (mb);
106 mono_mb_add_local (MonoMethodBuilder *mb, MonoType *type)
108 int res;
110 g_assert (mb != NULL);
111 g_assert (type != NULL);
113 res = mb->locals;
114 mb->locals_list = g_list_append (mb->locals_list, type);
115 mb->locals++;
117 return res;
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.
128 MonoMethod *
129 mono_mb_create_method (MonoMethodBuilder *mb, MonoMethodSignature *signature, int max_stack)
131 MonoMethodHeader *header;
132 MonoMethodWrapper *mw;
133 MonoImage *image;
134 MonoMethod *method;
135 GList *l;
136 int i;
138 g_assert (mb != NULL);
140 image = mb->method->klass->image;
142 mono_loader_lock (); /*FIXME I think this lock can go.*/
143 if (mb->dynamic) {
144 method = mb->method;
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);
158 } else {
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;
165 if (mb->no_dup_name)
166 method->name = mb->name;
167 else
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;
181 if (max_stack < 8)
182 max_stack = 8;
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);
198 if (i) {
199 GList *tmp;
200 void **data;
201 l = g_list_reverse (mw->method_data);
202 if (method->dynamic)
203 data = g_malloc (sizeof (gpointer) * (i + 1));
204 else
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);
208 i = 1;
209 for (tmp = l; tmp; tmp = tmp->next) {
210 data [i++] = tmp->data;
212 g_list_free (l);
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));
227 #endif
229 mono_loader_unlock ();
230 return method;
233 guint32
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);
248 void
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;
257 void
258 mono_mb_patch_addr_s (MonoMethodBuilder *mb, int pos, gint8 value)
260 *((gint8 *)(&mb->code [pos])) = value;
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 = g_realloc (mb->code, mb->code_size);
271 mb->code [mb->pos++] = op;
274 void
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);
280 if (offset) {
281 mono_mb_emit_icon (mb, offset);
282 mono_mb_emit_byte (mb, CEE_ADD);
286 void
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);
295 mb->pos += 4;
298 void
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;
308 mb->pos += 2;
311 void
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));
318 void
319 mono_mb_emit_ldstr (MonoMethodBuilder *mb, char *str)
321 mono_mb_emit_op (mb, CEE_LDSTR, str);
324 void
325 mono_mb_emit_ldarg (MonoMethodBuilder *mb, guint argnum)
327 if (argnum < 4) {
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);
332 } else {
333 mono_mb_emit_byte (mb, CEE_PREFIX1);
334 mono_mb_emit_byte (mb, CEE_LDARG);
335 mono_mb_emit_i2 (mb, argnum);
339 void
340 mono_mb_emit_ldarg_addr (MonoMethodBuilder *mb, guint argnum)
342 if (argnum < 256) {
343 mono_mb_emit_byte (mb, CEE_LDARGA_S);
344 mono_mb_emit_byte (mb, argnum);
345 } else {
346 mono_mb_emit_byte (mb, CEE_PREFIX1);
347 mono_mb_emit_byte (mb, CEE_LDARGA);
348 mono_mb_emit_i2 (mb, argnum);
352 void
353 mono_mb_emit_ldloc_addr (MonoMethodBuilder *mb, guint locnum)
355 if (locnum < 256) {
356 mono_mb_emit_byte (mb, CEE_LDLOCA_S);
357 mono_mb_emit_byte (mb, locnum);
358 } else {
359 mono_mb_emit_byte (mb, CEE_PREFIX1);
360 mono_mb_emit_byte (mb, CEE_LDLOCA);
361 mono_mb_emit_i2 (mb, locnum);
365 void
366 mono_mb_emit_ldloc (MonoMethodBuilder *mb, guint num)
368 if (num < 4) {
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);
373 } else {
374 mono_mb_emit_byte (mb, CEE_PREFIX1);
375 mono_mb_emit_byte (mb, CEE_LDLOC);
376 mono_mb_emit_i2 (mb, num);
380 void
381 mono_mb_emit_stloc (MonoMethodBuilder *mb, guint num)
383 if (num < 4) {
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);
388 } else {
389 mono_mb_emit_byte (mb, CEE_PREFIX1);
390 mono_mb_emit_byte (mb, CEE_STLOC);
391 mono_mb_emit_i2 (mb, num);
395 void
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);
403 } else {
404 mono_mb_emit_byte (mb, CEE_LDC_I4);
405 mono_mb_emit_i4 (mb, value);
410 mono_mb_get_label (MonoMethodBuilder *mb)
412 return mb->pos;
416 mono_mb_get_pos (MonoMethodBuilder *mb)
418 return mb->pos;
421 guint32
422 mono_mb_emit_branch (MonoMethodBuilder *mb, guint8 op)
424 guint32 res;
425 mono_mb_emit_byte (mb, op);
426 res = mb->pos;
427 mono_mb_emit_i4 (mb, 0);
428 return res;
431 guint32
432 mono_mb_emit_short_branch (MonoMethodBuilder *mb, guint8 op)
434 guint32 res;
435 mono_mb_emit_byte (mb, op);
436 res = mb->pos;
437 mono_mb_emit_byte (mb, 0);
439 return res;
442 void
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));
449 void
450 mono_mb_patch_branch (MonoMethodBuilder *mb, guint32 pos)
452 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
455 void
456 mono_mb_patch_short_branch (MonoMethodBuilder *mb, guint32 pos)
458 mono_mb_patch_addr_s (mb, pos, mb->pos - (pos + 1));
461 void
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);
468 void
469 mono_mb_emit_calli (MonoMethodBuilder *mb, MonoMethodSignature *sig)
471 mono_mb_emit_op (mb, CEE_CALLI, sig);
474 void
475 mono_mb_emit_managed_call (MonoMethodBuilder *mb, MonoMethod *method, MonoMethodSignature *opt_sig)
477 mono_mb_emit_op (mb, CEE_CALL, method);
480 void
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);
487 void
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);
494 void
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);
502 g_assert (ctor);
503 mono_mb_emit_op (mb, CEE_NEWOBJ, ctor);
504 if (msg != NULL) {
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);
513 void
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);
519 void
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);
528 void
529 mono_mb_set_clauses (MonoMethodBuilder *mb, int num_clauses, MonoExceptionClause *clauses)
531 mb->num_clauses = num_clauses;
532 mb->clauses = clauses;