2009-08-11 Gonzalo Paniagua Javier <gonzalo@novell.com>
[mono.git] / mono / metadata / method-builder.c
1 /*
2  * method-builder.c: Functions for creating IL methods at runtime.
3  * 
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *
7  * Copyright 2002-2003 Ximian, Inc (http://www.ximian.com)
8  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
9  */
10
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>
22
23 /* #define DEBUG_RUNTIME_CODE */
24
25 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
26         a = i,
27
28 enum {
29 #include "mono/cil/opcode.def"
30         LAST = 0xff
31 };
32 #undef OPDEF
33
34 #ifdef DEBUG_RUNTIME_CODE
35 static char*
36 indenter (MonoDisHelper *dh, MonoMethod *method, guint32 ip_offset)
37 {
38         return g_strdup (" ");
39 }
40
41 static MonoDisHelper marshal_dh = {
42         "\n",
43         "IL_%04x: ",
44         "IL_%04x",
45         indenter, 
46         NULL,
47         NULL
48 };
49 #endif 
50
51 static MonoMethodBuilder *
52 mono_mb_new_base (MonoClass *klass, MonoWrapperType type)
53 {
54         MonoMethodBuilder *mb;
55         MonoMethod *m;
56
57         g_assert (klass != NULL);
58
59         mb = g_new0 (MonoMethodBuilder, 1);
60
61         mb->method = m = (MonoMethod *)g_new0 (MonoMethodWrapper, 1);
62
63         m->klass = klass;
64         m->inline_info = 1;
65         m->wrapper_type = type;
66
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);
71
72         return mb;
73 }
74
75 MonoMethodBuilder *
76 mono_mb_new_no_dup_name (MonoClass *klass, const char *name, MonoWrapperType type)
77 {
78         MonoMethodBuilder *mb = mono_mb_new_base (klass, type);
79         mb->name = (char*)name;
80         mb->no_dup_name = TRUE;
81         return mb;
82 }
83
84 MonoMethodBuilder *
85 mono_mb_new (MonoClass *klass, const char *name, MonoWrapperType type)
86 {
87         MonoMethodBuilder *mb = mono_mb_new_base (klass, type);
88         mb->name = g_strdup (name);
89         return mb;
90 }
91
92 void
93 mono_mb_free (MonoMethodBuilder *mb)
94 {
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);
101         }
102         g_free (mb);
103 }
104
105 int
106 mono_mb_add_local (MonoMethodBuilder *mb, MonoType *type)
107 {
108         int res;
109
110         g_assert (mb != NULL);
111         g_assert (type != NULL);
112
113         res = mb->locals;
114         mb->locals_list = g_list_append (mb->locals_list, type);
115         mb->locals++;
116
117         return res;
118 }
119
120 /**
121  * mono_mb_create_method:
122  *
123  * Create a MonoMethod from this method builder.
124  * Returns: the newly created method.
125  *
126  * LOCKING: Takes the loader lock.
127  */
128 MonoMethod *
129 mono_mb_create_method (MonoMethodBuilder *mb, MonoMethodSignature *signature, int max_stack)
130 {
131         MonoMethodHeader *header;
132         MonoMethodWrapper *mw;
133         MonoImage *image;
134         MonoMethod *method;
135         GList *l;
136         int i;
137
138         g_assert (mb != NULL);
139
140         image = mb->method->klass->image;
141
142         mono_loader_lock (); /*FIXME I think this lock can go.*/
143         if (mb->dynamic) {
144                 method = mb->method;
145
146                 method->name = mb->name;
147                 method->dynamic = TRUE;
148
149                 ((MonoMethodNormal *)method)->header = header = (MonoMethodHeader *) 
150                         g_malloc0 (MONO_SIZEOF_METHOD_HEADER + mb->locals * sizeof (MonoType *));
151
152                 header->code = mb->code;
153
154                 for (i = 0, l = mb->locals_list; l; l = l->next, i++) {
155                         header->locals [i] = mono_metadata_type_dup (NULL, (MonoType*)l->data);
156                 }
157         } else {
158                 /* Realloc the method info into a mempool */
159
160                 method = mono_image_alloc0 (image, sizeof (MonoMethodWrapper));
161                 memcpy (method, mb->method, sizeof (MonoMethodWrapper));
162
163                 if (mb->no_dup_name)
164                         method->name = mb->name;
165                 else
166                         method->name = mono_image_strdup (image, mb->name);
167
168                 ((MonoMethodNormal *)method)->header = header = (MonoMethodHeader *) 
169                         mono_image_alloc0 (image, MONO_SIZEOF_METHOD_HEADER + mb->locals * sizeof (MonoType *));
170
171                 header->code = mono_image_alloc (image, mb->pos);
172                 memcpy ((char*)header->code, mb->code, mb->pos);
173
174                 for (i = 0, l = mb->locals_list; l; l = l->next, i++) {
175                         header->locals [i] = (MonoType *)l->data;
176                 }
177         }
178
179         if (max_stack < 8)
180                 max_stack = 8;
181
182         header->max_stack = max_stack;
183
184         method->signature = signature;
185
186         header->code_size = mb->pos;
187         header->num_locals = mb->locals;
188         header->init_locals = TRUE;
189
190         header->num_clauses = mb->num_clauses;
191         header->clauses = mb->clauses;
192
193         method->skip_visibility = mb->skip_visibility;
194
195         mw = (MonoMethodWrapper*) mb->method;
196         i = g_list_length (mw->method_data);
197         if (i) {
198                 GList *tmp;
199                 void **data;
200                 l = g_list_reverse (mw->method_data);
201                 if (method->dynamic)
202                         data = g_malloc (sizeof (gpointer) * (i + 1));
203                 else
204                         data = mono_image_alloc (image, sizeof (gpointer) * (i + 1));
205                 /* store the size in the first element */
206                 data [0] = GUINT_TO_POINTER (i);
207                 i = 1;
208                 for (tmp = l; tmp; tmp = tmp->next) {
209                         data [i++] = tmp->data;
210                 }
211                 g_list_free (l);
212
213                 ((MonoMethodWrapper*)method)->method_data = data;
214         }
215         /*{
216                 static int total_code = 0;
217                 static int total_alloc = 0;
218                 total_code += mb->pos;
219                 total_alloc += mb->code_size;
220                 g_print ("code size: %d of %d (allocated: %d)\n", mb->pos, total_code, total_alloc);
221         }*/
222
223 #ifdef DEBUG_RUNTIME_CODE
224         printf ("RUNTIME CODE FOR %s\n", mono_method_full_name (method, TRUE));
225         printf ("%s\n", mono_disasm_code (&marshal_dh, method, mb->code, mb->code + mb->pos));
226 #endif
227
228         mono_loader_unlock ();
229         return method;
230 }
231
232 guint32
233 mono_mb_add_data (MonoMethodBuilder *mb, gpointer data)
234 {
235         MonoMethodWrapper *mw;
236
237         g_assert (mb != NULL);
238
239         mw = (MonoMethodWrapper *)mb->method;
240
241         /* one O(n) is enough */
242         mw->method_data = g_list_prepend (mw->method_data, data);
243
244         return g_list_length (mw->method_data);
245 }
246
247 void
248 mono_mb_patch_addr (MonoMethodBuilder *mb, int pos, int value)
249 {
250         mb->code [pos] = value & 0xff;
251         mb->code [pos + 1] = (value >> 8) & 0xff;
252         mb->code [pos + 2] = (value >> 16) & 0xff;
253         mb->code [pos + 3] = (value >> 24) & 0xff;
254 }
255
256 void
257 mono_mb_patch_addr_s (MonoMethodBuilder *mb, int pos, gint8 value)
258 {
259         *((gint8 *)(&mb->code [pos])) = value;
260 }
261
262 void
263 mono_mb_emit_byte (MonoMethodBuilder *mb, guint8 op)
264 {
265         if (mb->pos >= mb->code_size) {
266                 mb->code_size += mb->code_size >> 1;
267                 mb->code = g_realloc (mb->code, mb->code_size);
268         }
269
270         mb->code [mb->pos++] = op;
271 }
272
273 void
274 mono_mb_emit_ldflda (MonoMethodBuilder *mb, gint32 offset)
275 {
276         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
277         mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
278
279         if (offset) {
280                 mono_mb_emit_icon (mb, offset);
281                 mono_mb_emit_byte (mb, CEE_ADD);
282         }
283 }
284
285 void
286 mono_mb_emit_i4 (MonoMethodBuilder *mb, gint32 data)
287 {
288         if ((mb->pos + 4) >= mb->code_size) {
289                 mb->code_size += mb->code_size >> 1;
290                 mb->code = g_realloc (mb->code, mb->code_size);
291         }
292
293         mono_mb_patch_addr (mb, mb->pos, data);
294         mb->pos += 4;
295 }
296
297 void
298 mono_mb_emit_i2 (MonoMethodBuilder *mb, gint16 data)
299 {
300         if ((mb->pos + 2) >= mb->code_size) {
301                 mb->code_size += mb->code_size >> 1;
302                 mb->code = g_realloc (mb->code, mb->code_size);
303         }
304
305         mb->code [mb->pos] = data & 0xff;
306         mb->code [mb->pos + 1] = (data >> 8) & 0xff;
307         mb->pos += 2;
308 }
309
310 void
311 mono_mb_emit_op (MonoMethodBuilder *mb, guint8 op, gpointer data)
312 {
313         mono_mb_emit_byte (mb, op);
314         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, data));
315 }
316
317 void
318 mono_mb_emit_ldstr (MonoMethodBuilder *mb, char *str)
319 {
320         mono_mb_emit_op (mb, CEE_LDSTR, str);
321 }
322
323 void
324 mono_mb_emit_ldarg (MonoMethodBuilder *mb, guint argnum)
325 {
326         if (argnum < 4) {
327                 mono_mb_emit_byte (mb, CEE_LDARG_0 + argnum);
328         } else if (argnum < 256) {
329                 mono_mb_emit_byte (mb, CEE_LDARG_S);
330                 mono_mb_emit_byte (mb, argnum);
331         } else {
332                 mono_mb_emit_byte (mb, CEE_PREFIX1);
333                 mono_mb_emit_byte (mb, CEE_LDARG);
334                 mono_mb_emit_i2 (mb, argnum);
335         }
336 }
337
338 void
339 mono_mb_emit_ldarg_addr (MonoMethodBuilder *mb, guint argnum)
340 {
341         if (argnum < 256) {
342                 mono_mb_emit_byte (mb, CEE_LDARGA_S);
343                 mono_mb_emit_byte (mb, argnum);
344         } else {
345                 mono_mb_emit_byte (mb, CEE_PREFIX1);
346                 mono_mb_emit_byte (mb, CEE_LDARGA);
347                 mono_mb_emit_i2 (mb, argnum);
348         }
349 }
350
351 void
352 mono_mb_emit_ldloc_addr (MonoMethodBuilder *mb, guint locnum)
353 {
354         if (locnum < 256) {
355                 mono_mb_emit_byte (mb, CEE_LDLOCA_S);
356                 mono_mb_emit_byte (mb, locnum);
357         } else {
358                 mono_mb_emit_byte (mb, CEE_PREFIX1);
359                 mono_mb_emit_byte (mb, CEE_LDLOCA);
360                 mono_mb_emit_i2 (mb, locnum);
361         }
362 }
363
364 void
365 mono_mb_emit_ldloc (MonoMethodBuilder *mb, guint num)
366 {
367         if (num < 4) {
368                 mono_mb_emit_byte (mb, CEE_LDLOC_0 + num);
369         } else if (num < 256) {
370                 mono_mb_emit_byte (mb, CEE_LDLOC_S);
371                 mono_mb_emit_byte (mb, num);
372         } else {
373                 mono_mb_emit_byte (mb, CEE_PREFIX1);
374                 mono_mb_emit_byte (mb, CEE_LDLOC);
375                 mono_mb_emit_i2 (mb, num);
376         }
377 }
378
379 void
380 mono_mb_emit_stloc (MonoMethodBuilder *mb, guint num)
381 {
382         if (num < 4) {
383                 mono_mb_emit_byte (mb, CEE_STLOC_0 + num);
384         } else if (num < 256) {
385                 mono_mb_emit_byte (mb, CEE_STLOC_S);
386                 mono_mb_emit_byte (mb, num);
387         } else {
388                 mono_mb_emit_byte (mb, CEE_PREFIX1);
389                 mono_mb_emit_byte (mb, CEE_STLOC);
390                 mono_mb_emit_i2 (mb, num);
391         }
392 }
393
394 void
395 mono_mb_emit_icon (MonoMethodBuilder *mb, gint32 value)
396 {
397         if (value >= -1 && value < 8) {
398                 mono_mb_emit_byte (mb, CEE_LDC_I4_0 + value);
399         } else if (value >= -128 && value <= 127) {
400                 mono_mb_emit_byte (mb, CEE_LDC_I4_S);
401                 mono_mb_emit_byte (mb, value);
402         } else {
403                 mono_mb_emit_byte (mb, CEE_LDC_I4);
404                 mono_mb_emit_i4 (mb, value);
405         }
406 }
407
408 int
409 mono_mb_get_label (MonoMethodBuilder *mb)
410 {
411         return mb->pos;
412 }
413
414 int
415 mono_mb_get_pos (MonoMethodBuilder *mb)
416 {
417         return mb->pos;
418 }
419
420 guint32
421 mono_mb_emit_branch (MonoMethodBuilder *mb, guint8 op)
422 {
423         guint32 res;
424         mono_mb_emit_byte (mb, op);
425         res = mb->pos;
426         mono_mb_emit_i4 (mb, 0);
427         return res;
428 }
429
430 guint32
431 mono_mb_emit_short_branch (MonoMethodBuilder *mb, guint8 op)
432 {
433         guint32 res;
434         mono_mb_emit_byte (mb, op);
435         res = mb->pos;
436         mono_mb_emit_byte (mb, 0);
437
438         return res;
439 }
440
441 void
442 mono_mb_emit_branch_label (MonoMethodBuilder *mb, guint8 op, guint32 label)
443 {
444         mono_mb_emit_byte (mb, op);
445         mono_mb_emit_i4 (mb, label - (mb->pos + 4));
446 }
447
448 void
449 mono_mb_patch_branch (MonoMethodBuilder *mb, guint32 pos)
450 {
451         mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
452 }
453
454 void
455 mono_mb_patch_short_branch (MonoMethodBuilder *mb, guint32 pos)
456 {
457         mono_mb_patch_addr_s (mb, pos, mb->pos - (pos + 1));
458 }
459
460 void
461 mono_mb_emit_ptr (MonoMethodBuilder *mb, gpointer ptr)
462 {
463         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
464         mono_mb_emit_op (mb, CEE_MONO_LDPTR, ptr);
465 }
466
467 void
468 mono_mb_emit_calli (MonoMethodBuilder *mb, MonoMethodSignature *sig)
469 {
470         mono_mb_emit_op (mb, CEE_CALLI, sig);
471 }
472
473 void
474 mono_mb_emit_managed_call (MonoMethodBuilder *mb, MonoMethod *method, MonoMethodSignature *opt_sig)
475 {
476         mono_mb_emit_op (mb, CEE_CALL, method);
477 }
478
479 void
480 mono_mb_emit_native_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, gpointer func)
481 {
482         mono_mb_emit_ptr (mb, func);
483         mono_mb_emit_calli (mb, sig);
484 }
485
486 void
487 mono_mb_emit_icall (MonoMethodBuilder *mb, gpointer func)
488 {
489         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
490         mono_mb_emit_op (mb, CEE_MONO_ICALL, func);
491 }
492
493 void
494 mono_mb_emit_exception_full (MonoMethodBuilder *mb, const char *exc_nspace, const char *exc_name, const char *msg)
495 {
496         MonoMethod *ctor = NULL;
497
498         MonoClass *mme = mono_class_from_name (mono_defaults.corlib, exc_nspace, exc_name);
499         mono_class_init (mme);
500         ctor = mono_class_get_method_from_name (mme, ".ctor", 0);
501         g_assert (ctor);
502         mono_mb_emit_op (mb, CEE_NEWOBJ, ctor);
503         if (msg != NULL) {
504                 mono_mb_emit_byte (mb, CEE_DUP);
505                 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoException, message));
506                 mono_mb_emit_ldstr (mb, (char*)msg);
507                 mono_mb_emit_byte (mb, CEE_STIND_REF);
508         }
509         mono_mb_emit_byte (mb, CEE_THROW);
510 }
511
512 void
513 mono_mb_emit_exception (MonoMethodBuilder *mb, const char *exc_name, const char *msg)
514 {
515         mono_mb_emit_exception_full (mb, "System", exc_name, msg);
516 }
517
518 void
519 mono_mb_emit_add_to_local (MonoMethodBuilder *mb, guint16 local, gint32 incr)
520 {
521         mono_mb_emit_ldloc (mb, local); 
522         mono_mb_emit_icon (mb, incr);
523         mono_mb_emit_byte (mb, CEE_ADD);
524         mono_mb_emit_stloc (mb, local); 
525 }
526
527 void
528 mono_mb_set_clauses (MonoMethodBuilder *mb, int num_clauses, MonoExceptionClause *clauses)
529 {
530         mb->num_clauses = num_clauses;
531         mb->clauses = clauses;
532 }