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