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