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