Merge pull request #2820 from kumpera/license-change-rebased
[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  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
10  */
11
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>
24
25 /* #define DEBUG_RUNTIME_CODE */
26
27 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
28         a = i,
29
30 enum {
31 #include "mono/cil/opcode.def"
32         LAST = 0xff
33 };
34 #undef OPDEF
35
36 #ifdef DEBUG_RUNTIME_CODE
37 static char*
38 indenter (MonoDisHelper *dh, MonoMethod *method, guint32 ip_offset)
39 {
40         return g_strdup (" ");
41 }
42
43 static MonoDisHelper marshal_dh = {
44         "\n",
45         "IL_%04x: ",
46         "IL_%04x",
47         indenter, 
48         NULL,
49         NULL
50 };
51 #endif 
52
53 static MonoMethodBuilder *
54 mono_mb_new_base (MonoClass *klass, MonoWrapperType type)
55 {
56         MonoMethodBuilder *mb;
57         MonoMethod *m;
58
59         g_assert (klass != NULL);
60
61         mb = g_new0 (MonoMethodBuilder, 1);
62
63         mb->method = m = (MonoMethod *)g_new0 (MonoMethodWrapper, 1);
64
65         m->klass = klass;
66         m->inline_info = 1;
67         m->wrapper_type = type;
68
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);
76
77         return mb;
78 }
79
80 MonoMethodBuilder *
81 mono_mb_new_no_dup_name (MonoClass *klass, const char *name, MonoWrapperType type)
82 {
83         MonoMethodBuilder *mb = mono_mb_new_base (klass, type);
84         mb->name = (char*)name;
85         mb->no_dup_name = TRUE;
86         return mb;
87 }
88
89 MonoMethodBuilder *
90 mono_mb_new (MonoClass *klass, const char *name, MonoWrapperType type)
91 {
92         MonoMethodBuilder *mb = mono_mb_new_base (klass, type);
93         mb->name = g_strdup (name);
94         return mb;
95 }
96
97 void
98 mono_mb_free (MonoMethodBuilder *mb)
99 {
100 #ifndef DISABLE_JIT
101         g_list_free (mb->locals_list);
102         if (!mb->dynamic) {
103                 g_free (mb->method);
104                 if (!mb->no_dup_name)
105                         g_free (mb->name);
106                 g_free (mb->code);
107         }
108 #else
109         g_free (mb->method);
110         if (!mb->no_dup_name)
111                 g_free (mb->name);
112 #endif
113         g_free (mb);
114 }
115
116 /**
117  * mono_mb_create_method:
118  *
119  * Create a MonoMethod from this method builder.
120  * Returns: the newly created method.
121  *
122  */
123 MonoMethod *
124 mono_mb_create_method (MonoMethodBuilder *mb, MonoMethodSignature *signature, int max_stack)
125 {
126 #ifndef DISABLE_JIT
127         MonoMethodHeader *header;
128 #endif
129         MonoMethodWrapper *mw;
130         MonoImage *image;
131         MonoMethod *method;
132         GList *l;
133         int i;
134
135         g_assert (mb != NULL);
136
137         image = mb->method->klass->image;
138
139 #ifndef DISABLE_JIT
140         if (mb->dynamic) {
141                 method = mb->method;
142                 mw = (MonoMethodWrapper*)method;
143
144                 method->name = mb->name;
145                 method->dynamic = TRUE;
146
147                 mw->header = header = (MonoMethodHeader *) 
148                         g_malloc0 (MONO_SIZEOF_METHOD_HEADER + 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 #endif
157         {
158                 /* Realloc the method info into a mempool */
159
160                 method = (MonoMethod *)mono_image_alloc0 (image, sizeof (MonoMethodWrapper));
161                 memcpy (method, mb->method, sizeof (MonoMethodWrapper));
162                 mw = (MonoMethodWrapper*) method;
163
164                 if (mb->no_dup_name)
165                         method->name = mb->name;
166                 else
167                         method->name = mono_image_strdup (image, mb->name);
168
169 #ifndef DISABLE_JIT
170                 mw->header = header = (MonoMethodHeader *) 
171                         mono_image_alloc0 (image, MONO_SIZEOF_METHOD_HEADER + mb->locals * sizeof (MonoType *));
172
173                 header->code = (const unsigned char *)mono_image_alloc (image, mb->pos);
174                 memcpy ((char*)header->code, mb->code, mb->pos);
175
176                 for (i = 0, l = mb->locals_list; l; l = l->next, i++) {
177                         header->locals [i] = mono_metadata_type_dup (NULL, (MonoType*)l->data);
178                 }
179 #endif
180         }
181
182         method->signature = signature;
183         if (!signature->hasthis)
184                 method->flags |= METHOD_ATTRIBUTE_STATIC;
185
186 #ifndef DISABLE_JIT
187         if (max_stack < 8)
188                 max_stack = 8;
189
190         header->max_stack = max_stack;
191
192         header->code_size = mb->pos;
193         header->num_locals = mb->locals;
194         header->init_locals = mb->init_locals;
195
196         header->num_clauses = mb->num_clauses;
197         header->clauses = mb->clauses;
198
199         method->skip_visibility = mb->skip_visibility;
200 #endif
201
202         i = g_list_length ((GList *)mw->method_data);
203         if (i) {
204                 GList *tmp;
205                 void **data;
206                 l = g_list_reverse ((GList *)mw->method_data);
207                 if (method_is_dynamic (method))
208                         data = (void **)g_malloc (sizeof (gpointer) * (i + 1));
209                 else
210                         data = (void **)mono_image_alloc (image, sizeof (gpointer) * (i + 1));
211                 /* store the size in the first element */
212                 data [0] = GUINT_TO_POINTER (i);
213                 i = 1;
214                 for (tmp = l; tmp; tmp = tmp->next) {
215                         data [i++] = tmp->data;
216                 }
217                 g_list_free (l);
218
219                 mw->method_data = data;
220         }
221
222 #ifndef DISABLE_JIT
223         /*{
224                 static int total_code = 0;
225                 static int total_alloc = 0;
226                 total_code += mb->pos;
227                 total_alloc += mb->code_size;
228                 g_print ("code size: %d of %d (allocated: %d)\n", mb->pos, total_code, total_alloc);
229         }*/
230
231 #ifdef DEBUG_RUNTIME_CODE
232         printf ("RUNTIME CODE FOR %s\n", mono_method_full_name (method, TRUE));
233         printf ("%s\n", mono_disasm_code (&marshal_dh, method, mb->code, mb->code + mb->pos));
234 #endif
235
236         if (mb->param_names) {
237                 char **param_names = (char **)mono_image_alloc0 (image, signature->param_count * sizeof (gpointer));
238                 for (i = 0; i < signature->param_count; ++i)
239                         param_names [i] = mono_image_strdup (image, mb->param_names [i]);
240
241                 mono_image_lock (image);
242                 if (!image->wrapper_param_names)
243                         image->wrapper_param_names = g_hash_table_new (NULL, NULL);
244                 g_hash_table_insert (image->wrapper_param_names, method, param_names);
245                 mono_image_unlock (image);
246         }
247 #endif
248
249         return method;
250 }
251
252 guint32
253 mono_mb_add_data (MonoMethodBuilder *mb, gpointer data)
254 {
255         MonoMethodWrapper *mw;
256
257         g_assert (mb != NULL);
258
259         mw = (MonoMethodWrapper *)mb->method;
260
261         /* one O(n) is enough */
262         mw->method_data = g_list_prepend ((GList *)mw->method_data, data);
263
264         return g_list_length ((GList *)mw->method_data);
265 }
266
267 #ifndef DISABLE_JIT
268
269 int
270 mono_mb_add_local (MonoMethodBuilder *mb, MonoType *type)
271 {
272         int res;
273
274         g_assert (mb != NULL);
275         g_assert (type != NULL);
276
277         res = mb->locals;
278         mb->locals_list = g_list_append (mb->locals_list, type);
279         mb->locals++;
280
281         return res;
282 }
283
284 void
285 mono_mb_patch_addr (MonoMethodBuilder *mb, int pos, int value)
286 {
287         mb->code [pos] = value & 0xff;
288         mb->code [pos + 1] = (value >> 8) & 0xff;
289         mb->code [pos + 2] = (value >> 16) & 0xff;
290         mb->code [pos + 3] = (value >> 24) & 0xff;
291 }
292
293 void
294 mono_mb_patch_addr_s (MonoMethodBuilder *mb, int pos, gint8 value)
295 {
296         *((gint8 *)(&mb->code [pos])) = value;
297 }
298
299 void
300 mono_mb_emit_byte (MonoMethodBuilder *mb, guint8 op)
301 {
302         if (mb->pos >= mb->code_size) {
303                 mb->code_size += mb->code_size >> 1;
304                 mb->code = (unsigned char *)g_realloc (mb->code, mb->code_size);
305         }
306
307         mb->code [mb->pos++] = op;
308 }
309
310 void
311 mono_mb_emit_ldflda (MonoMethodBuilder *mb, gint32 offset)
312 {
313         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
314         mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
315
316         if (offset) {
317                 mono_mb_emit_icon (mb, offset);
318                 mono_mb_emit_byte (mb, CEE_ADD);
319         }
320 }
321
322 void
323 mono_mb_emit_i4 (MonoMethodBuilder *mb, gint32 data)
324 {
325         if ((mb->pos + 4) >= mb->code_size) {
326                 mb->code_size += mb->code_size >> 1;
327                 mb->code = (unsigned char *)g_realloc (mb->code, mb->code_size);
328         }
329
330         mono_mb_patch_addr (mb, mb->pos, data);
331         mb->pos += 4;
332 }
333
334 void
335 mono_mb_emit_i8 (MonoMethodBuilder *mb, gint64 data)
336 {
337         if ((mb->pos + 8) >= mb->code_size) {
338                 mb->code_size += mb->code_size >> 1;
339                 mb->code = (unsigned char *)g_realloc (mb->code, mb->code_size);
340         }
341
342         mono_mb_patch_addr (mb, mb->pos, data);
343         mono_mb_patch_addr (mb, mb->pos + 4, data >> 32);
344         mb->pos += 8;
345 }
346
347 void
348 mono_mb_emit_i2 (MonoMethodBuilder *mb, gint16 data)
349 {
350         if ((mb->pos + 2) >= mb->code_size) {
351                 mb->code_size += mb->code_size >> 1;
352                 mb->code = (unsigned char *)g_realloc (mb->code, mb->code_size);
353         }
354
355         mb->code [mb->pos] = data & 0xff;
356         mb->code [mb->pos + 1] = (data >> 8) & 0xff;
357         mb->pos += 2;
358 }
359
360 void
361 mono_mb_emit_op (MonoMethodBuilder *mb, guint8 op, gpointer data)
362 {
363         mono_mb_emit_byte (mb, op);
364         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, data));
365 }
366
367 void
368 mono_mb_emit_ldstr (MonoMethodBuilder *mb, char *str)
369 {
370         mono_mb_emit_op (mb, CEE_LDSTR, str);
371 }
372
373 void
374 mono_mb_emit_ldarg (MonoMethodBuilder *mb, guint argnum)
375 {
376         if (argnum < 4) {
377                 mono_mb_emit_byte (mb, CEE_LDARG_0 + argnum);
378         } else if (argnum < 256) {
379                 mono_mb_emit_byte (mb, CEE_LDARG_S);
380                 mono_mb_emit_byte (mb, argnum);
381         } else {
382                 mono_mb_emit_byte (mb, CEE_PREFIX1);
383                 mono_mb_emit_byte (mb, CEE_LDARG);
384                 mono_mb_emit_i2 (mb, argnum);
385         }
386 }
387
388 void
389 mono_mb_emit_ldarg_addr (MonoMethodBuilder *mb, guint argnum)
390 {
391         if (argnum < 256) {
392                 mono_mb_emit_byte (mb, CEE_LDARGA_S);
393                 mono_mb_emit_byte (mb, argnum);
394         } else {
395                 mono_mb_emit_byte (mb, CEE_PREFIX1);
396                 mono_mb_emit_byte (mb, CEE_LDARGA);
397                 mono_mb_emit_i2 (mb, argnum);
398         }
399 }
400
401 void
402 mono_mb_emit_ldloc_addr (MonoMethodBuilder *mb, guint locnum)
403 {
404         if (locnum < 256) {
405                 mono_mb_emit_byte (mb, CEE_LDLOCA_S);
406                 mono_mb_emit_byte (mb, locnum);
407         } else {
408                 mono_mb_emit_byte (mb, CEE_PREFIX1);
409                 mono_mb_emit_byte (mb, CEE_LDLOCA);
410                 mono_mb_emit_i2 (mb, locnum);
411         }
412 }
413
414 void
415 mono_mb_emit_ldloc (MonoMethodBuilder *mb, guint num)
416 {
417         if (num < 4) {
418                 mono_mb_emit_byte (mb, CEE_LDLOC_0 + num);
419         } else if (num < 256) {
420                 mono_mb_emit_byte (mb, CEE_LDLOC_S);
421                 mono_mb_emit_byte (mb, num);
422         } else {
423                 mono_mb_emit_byte (mb, CEE_PREFIX1);
424                 mono_mb_emit_byte (mb, CEE_LDLOC);
425                 mono_mb_emit_i2 (mb, num);
426         }
427 }
428
429 void
430 mono_mb_emit_stloc (MonoMethodBuilder *mb, guint num)
431 {
432         if (num < 4) {
433                 mono_mb_emit_byte (mb, CEE_STLOC_0 + num);
434         } else if (num < 256) {
435                 mono_mb_emit_byte (mb, CEE_STLOC_S);
436                 mono_mb_emit_byte (mb, num);
437         } else {
438                 mono_mb_emit_byte (mb, CEE_PREFIX1);
439                 mono_mb_emit_byte (mb, CEE_STLOC);
440                 mono_mb_emit_i2 (mb, num);
441         }
442 }
443
444 void
445 mono_mb_emit_icon (MonoMethodBuilder *mb, gint32 value)
446 {
447         if (value >= -1 && value < 8) {
448                 mono_mb_emit_byte (mb, CEE_LDC_I4_0 + value);
449         } else if (value >= -128 && value <= 127) {
450                 mono_mb_emit_byte (mb, CEE_LDC_I4_S);
451                 mono_mb_emit_byte (mb, value);
452         } else {
453                 mono_mb_emit_byte (mb, CEE_LDC_I4);
454                 mono_mb_emit_i4 (mb, value);
455         }
456 }
457
458 void
459 mono_mb_emit_icon8 (MonoMethodBuilder *mb, gint64 value)
460 {
461         mono_mb_emit_byte (mb, CEE_LDC_I8);
462         mono_mb_emit_i8 (mb, value);
463 }
464
465 int
466 mono_mb_get_label (MonoMethodBuilder *mb)
467 {
468         return mb->pos;
469 }
470
471 int
472 mono_mb_get_pos (MonoMethodBuilder *mb)
473 {
474         return mb->pos;
475 }
476
477 guint32
478 mono_mb_emit_branch (MonoMethodBuilder *mb, guint8 op)
479 {
480         guint32 res;
481         mono_mb_emit_byte (mb, op);
482         res = mb->pos;
483         mono_mb_emit_i4 (mb, 0);
484         return res;
485 }
486
487 guint32
488 mono_mb_emit_short_branch (MonoMethodBuilder *mb, guint8 op)
489 {
490         guint32 res;
491         mono_mb_emit_byte (mb, op);
492         res = mb->pos;
493         mono_mb_emit_byte (mb, 0);
494
495         return res;
496 }
497
498 void
499 mono_mb_emit_branch_label (MonoMethodBuilder *mb, guint8 op, guint32 label)
500 {
501         mono_mb_emit_byte (mb, op);
502         mono_mb_emit_i4 (mb, label - (mb->pos + 4));
503 }
504
505 void
506 mono_mb_patch_branch (MonoMethodBuilder *mb, guint32 pos)
507 {
508         mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
509 }
510
511 void
512 mono_mb_patch_short_branch (MonoMethodBuilder *mb, guint32 pos)
513 {
514         mono_mb_patch_addr_s (mb, pos, mb->pos - (pos + 1));
515 }
516
517 void
518 mono_mb_emit_ptr (MonoMethodBuilder *mb, gpointer ptr)
519 {
520         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
521         mono_mb_emit_op (mb, CEE_MONO_LDPTR, ptr);
522 }
523
524 void
525 mono_mb_emit_calli (MonoMethodBuilder *mb, MonoMethodSignature *sig)
526 {
527         mono_mb_emit_op (mb, CEE_CALLI, sig);
528 }
529
530 void
531 mono_mb_emit_managed_call (MonoMethodBuilder *mb, MonoMethod *method, MonoMethodSignature *opt_sig)
532 {
533         mono_mb_emit_op (mb, CEE_CALL, method);
534 }
535
536 void
537 mono_mb_emit_native_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, gpointer func)
538 {
539         mono_mb_emit_ptr (mb, func);
540         mono_mb_emit_calli (mb, sig);
541 }
542
543 void
544 mono_mb_emit_icall (MonoMethodBuilder *mb, gpointer func)
545 {
546         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
547         mono_mb_emit_op (mb, CEE_MONO_ICALL, func);
548 }
549
550 void
551 mono_mb_emit_exception_full (MonoMethodBuilder *mb, const char *exc_nspace, const char *exc_name, const char *msg)
552 {
553         MonoMethod *ctor = NULL;
554
555         MonoClass *mme = mono_class_load_from_name (mono_defaults.corlib, exc_nspace, exc_name);
556         mono_class_init (mme);
557         ctor = mono_class_get_method_from_name (mme, ".ctor", 0);
558         g_assert (ctor);
559         mono_mb_emit_op (mb, CEE_NEWOBJ, ctor);
560         if (msg != NULL) {
561                 mono_mb_emit_byte (mb, CEE_DUP);
562                 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoException, message));
563                 mono_mb_emit_ldstr (mb, (char*)msg);
564                 mono_mb_emit_byte (mb, CEE_STIND_REF);
565         }
566         mono_mb_emit_byte (mb, CEE_THROW);
567 }
568
569 void
570 mono_mb_emit_exception (MonoMethodBuilder *mb, const char *exc_name, const char *msg)
571 {
572         mono_mb_emit_exception_full (mb, "System", exc_name, msg);
573 }
574
575 void
576 mono_mb_emit_add_to_local (MonoMethodBuilder *mb, guint16 local, gint32 incr)
577 {
578         mono_mb_emit_ldloc (mb, local); 
579         mono_mb_emit_icon (mb, incr);
580         mono_mb_emit_byte (mb, CEE_ADD);
581         mono_mb_emit_stloc (mb, local); 
582 }
583
584 void
585 mono_mb_set_clauses (MonoMethodBuilder *mb, int num_clauses, MonoExceptionClause *clauses)
586 {
587         mb->num_clauses = num_clauses;
588         mb->clauses = clauses;
589 }
590
591 /*
592  * mono_mb_set_param_names:
593  *
594  *   PARAM_NAMES should have length equal to the sig->param_count, the caller retains
595  * ownership of the array, and its entries.
596  */
597 void
598 mono_mb_set_param_names (MonoMethodBuilder *mb, const char **param_names)
599 {
600         mb->param_names = param_names;
601 }
602
603 #endif /* DISABLE_JIT */