Merge pull request #707 from LHCGreg/12752-windows_nul_isredirected
[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  * LOCKING: Takes the loader lock.
120  */
121 MonoMethod *
122 mono_mb_create_method (MonoMethodBuilder *mb, MonoMethodSignature *signature, int max_stack)
123 {
124 #ifndef DISABLE_JIT
125         MonoMethodHeader *header;
126 #endif
127         MonoMethodWrapper *mw;
128         MonoImage *image;
129         MonoMethod *method;
130         GList *l;
131         int i;
132
133         g_assert (mb != NULL);
134
135         image = mb->method->klass->image;
136
137         mono_loader_lock (); /*FIXME I think this lock can go.*/
138 #ifndef DISABLE_JIT
139         if (mb->dynamic) {
140                 method = mb->method;
141                 mw = (MonoMethodWrapper*)method;
142
143                 method->name = mb->name;
144                 method->dynamic = TRUE;
145
146                 mw->header = header = (MonoMethodHeader *) 
147                         g_malloc0 (MONO_SIZEOF_METHOD_HEADER + mb->locals * sizeof (MonoType *));
148
149                 header->code = mb->code;
150
151                 for (i = 0, l = mb->locals_list; l; l = l->next, i++) {
152                         header->locals [i] = mono_metadata_type_dup (NULL, (MonoType*)l->data);
153                 }
154         } else
155 #endif
156         {
157                 /* Realloc the method info into a mempool */
158
159                 method = mono_image_alloc0 (image, sizeof (MonoMethodWrapper));
160                 memcpy (method, mb->method, sizeof (MonoMethodWrapper));
161                 mw = (MonoMethodWrapper*) method;
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 #ifndef DISABLE_JIT
169                 mw->header = header = (MonoMethodHeader *) 
170                         mono_image_alloc0 (image, MONO_SIZEOF_METHOD_HEADER + mb->locals * sizeof (MonoType *));
171
172                 header->code = mono_image_alloc (image, mb->pos);
173                 memcpy ((char*)header->code, mb->code, mb->pos);
174
175                 for (i = 0, l = mb->locals_list; l; l = l->next, i++) {
176                         header->locals [i] = (MonoType *)l->data;
177                 }
178 #endif
179         }
180
181         method->signature = signature;
182         if (!signature->hasthis)
183                 method->flags |= METHOD_ATTRIBUTE_STATIC;
184
185 #ifndef DISABLE_JIT
186         if (max_stack < 8)
187                 max_stack = 8;
188
189         header->max_stack = max_stack;
190
191         header->code_size = mb->pos;
192         header->num_locals = mb->locals;
193         header->init_locals = TRUE;
194
195         header->num_clauses = mb->num_clauses;
196         header->clauses = mb->clauses;
197
198         method->skip_visibility = mb->skip_visibility;
199 #endif
200
201         i = g_list_length (mw->method_data);
202         if (i) {
203                 GList *tmp;
204                 void **data;
205                 l = g_list_reverse (mw->method_data);
206                 if (method->dynamic)
207                         data = g_malloc (sizeof (gpointer) * (i + 1));
208                 else
209                         data = mono_image_alloc (image, sizeof (gpointer) * (i + 1));
210                 /* store the size in the first element */
211                 data [0] = GUINT_TO_POINTER (i);
212                 i = 1;
213                 for (tmp = l; tmp; tmp = tmp->next) {
214                         data [i++] = tmp->data;
215                 }
216                 g_list_free (l);
217
218                 mw->method_data = data;
219         }
220
221 #ifndef DISABLE_JIT
222         /*{
223                 static int total_code = 0;
224                 static int total_alloc = 0;
225                 total_code += mb->pos;
226                 total_alloc += mb->code_size;
227                 g_print ("code size: %d of %d (allocated: %d)\n", mb->pos, total_code, total_alloc);
228         }*/
229
230 #ifdef DEBUG_RUNTIME_CODE
231         printf ("RUNTIME CODE FOR %s\n", mono_method_full_name (method, TRUE));
232         printf ("%s\n", mono_disasm_code (&marshal_dh, method, mb->code, mb->code + mb->pos));
233 #endif
234
235         if (mb->param_names) {
236                 char **param_names = mono_image_alloc0 (image, signature->param_count * sizeof (gpointer));
237                 for (i = 0; i < signature->param_count; ++i)
238                         param_names [i] = mono_image_strdup (image, mb->param_names [i]);
239
240                 mono_image_lock (image);
241                 if (!image->wrapper_param_names)
242                         image->wrapper_param_names = g_hash_table_new (NULL, NULL);
243                 g_hash_table_insert (image->wrapper_param_names, method, param_names);
244                 mono_image_unlock (image);
245         }
246 #endif
247
248         mono_loader_unlock ();
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 (mw->method_data, data);
263
264         return g_list_length (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 = 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 = 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_i2 (MonoMethodBuilder *mb, gint16 data)
336 {
337         if ((mb->pos + 2) >= mb->code_size) {
338                 mb->code_size += mb->code_size >> 1;
339                 mb->code = g_realloc (mb->code, mb->code_size);
340         }
341
342         mb->code [mb->pos] = data & 0xff;
343         mb->code [mb->pos + 1] = (data >> 8) & 0xff;
344         mb->pos += 2;
345 }
346
347 void
348 mono_mb_emit_op (MonoMethodBuilder *mb, guint8 op, gpointer data)
349 {
350         mono_mb_emit_byte (mb, op);
351         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, data));
352 }
353
354 void
355 mono_mb_emit_ldstr (MonoMethodBuilder *mb, char *str)
356 {
357         mono_mb_emit_op (mb, CEE_LDSTR, str);
358 }
359
360 void
361 mono_mb_emit_ldarg (MonoMethodBuilder *mb, guint argnum)
362 {
363         if (argnum < 4) {
364                 mono_mb_emit_byte (mb, CEE_LDARG_0 + argnum);
365         } else if (argnum < 256) {
366                 mono_mb_emit_byte (mb, CEE_LDARG_S);
367                 mono_mb_emit_byte (mb, argnum);
368         } else {
369                 mono_mb_emit_byte (mb, CEE_PREFIX1);
370                 mono_mb_emit_byte (mb, CEE_LDARG);
371                 mono_mb_emit_i2 (mb, argnum);
372         }
373 }
374
375 void
376 mono_mb_emit_ldarg_addr (MonoMethodBuilder *mb, guint argnum)
377 {
378         if (argnum < 256) {
379                 mono_mb_emit_byte (mb, CEE_LDARGA_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_LDARGA);
384                 mono_mb_emit_i2 (mb, argnum);
385         }
386 }
387
388 void
389 mono_mb_emit_ldloc_addr (MonoMethodBuilder *mb, guint locnum)
390 {
391         if (locnum < 256) {
392                 mono_mb_emit_byte (mb, CEE_LDLOCA_S);
393                 mono_mb_emit_byte (mb, locnum);
394         } else {
395                 mono_mb_emit_byte (mb, CEE_PREFIX1);
396                 mono_mb_emit_byte (mb, CEE_LDLOCA);
397                 mono_mb_emit_i2 (mb, locnum);
398         }
399 }
400
401 void
402 mono_mb_emit_ldloc (MonoMethodBuilder *mb, guint num)
403 {
404         if (num < 4) {
405                 mono_mb_emit_byte (mb, CEE_LDLOC_0 + num);
406         } else if (num < 256) {
407                 mono_mb_emit_byte (mb, CEE_LDLOC_S);
408                 mono_mb_emit_byte (mb, num);
409         } else {
410                 mono_mb_emit_byte (mb, CEE_PREFIX1);
411                 mono_mb_emit_byte (mb, CEE_LDLOC);
412                 mono_mb_emit_i2 (mb, num);
413         }
414 }
415
416 void
417 mono_mb_emit_stloc (MonoMethodBuilder *mb, guint num)
418 {
419         if (num < 4) {
420                 mono_mb_emit_byte (mb, CEE_STLOC_0 + num);
421         } else if (num < 256) {
422                 mono_mb_emit_byte (mb, CEE_STLOC_S);
423                 mono_mb_emit_byte (mb, num);
424         } else {
425                 mono_mb_emit_byte (mb, CEE_PREFIX1);
426                 mono_mb_emit_byte (mb, CEE_STLOC);
427                 mono_mb_emit_i2 (mb, num);
428         }
429 }
430
431 void
432 mono_mb_emit_icon (MonoMethodBuilder *mb, gint32 value)
433 {
434         if (value >= -1 && value < 8) {
435                 mono_mb_emit_byte (mb, CEE_LDC_I4_0 + value);
436         } else if (value >= -128 && value <= 127) {
437                 mono_mb_emit_byte (mb, CEE_LDC_I4_S);
438                 mono_mb_emit_byte (mb, value);
439         } else {
440                 mono_mb_emit_byte (mb, CEE_LDC_I4);
441                 mono_mb_emit_i4 (mb, value);
442         }
443 }
444
445 int
446 mono_mb_get_label (MonoMethodBuilder *mb)
447 {
448         return mb->pos;
449 }
450
451 int
452 mono_mb_get_pos (MonoMethodBuilder *mb)
453 {
454         return mb->pos;
455 }
456
457 guint32
458 mono_mb_emit_branch (MonoMethodBuilder *mb, guint8 op)
459 {
460         guint32 res;
461         mono_mb_emit_byte (mb, op);
462         res = mb->pos;
463         mono_mb_emit_i4 (mb, 0);
464         return res;
465 }
466
467 guint32
468 mono_mb_emit_short_branch (MonoMethodBuilder *mb, guint8 op)
469 {
470         guint32 res;
471         mono_mb_emit_byte (mb, op);
472         res = mb->pos;
473         mono_mb_emit_byte (mb, 0);
474
475         return res;
476 }
477
478 void
479 mono_mb_emit_branch_label (MonoMethodBuilder *mb, guint8 op, guint32 label)
480 {
481         mono_mb_emit_byte (mb, op);
482         mono_mb_emit_i4 (mb, label - (mb->pos + 4));
483 }
484
485 void
486 mono_mb_patch_branch (MonoMethodBuilder *mb, guint32 pos)
487 {
488         mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
489 }
490
491 void
492 mono_mb_patch_short_branch (MonoMethodBuilder *mb, guint32 pos)
493 {
494         mono_mb_patch_addr_s (mb, pos, mb->pos - (pos + 1));
495 }
496
497 void
498 mono_mb_emit_ptr (MonoMethodBuilder *mb, gpointer ptr)
499 {
500         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
501         mono_mb_emit_op (mb, CEE_MONO_LDPTR, ptr);
502 }
503
504 void
505 mono_mb_emit_calli (MonoMethodBuilder *mb, MonoMethodSignature *sig)
506 {
507         mono_mb_emit_op (mb, CEE_CALLI, sig);
508 }
509
510 void
511 mono_mb_emit_managed_call (MonoMethodBuilder *mb, MonoMethod *method, MonoMethodSignature *opt_sig)
512 {
513         mono_mb_emit_op (mb, CEE_CALL, method);
514 }
515
516 void
517 mono_mb_emit_native_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, gpointer func)
518 {
519         mono_mb_emit_ptr (mb, func);
520         mono_mb_emit_calli (mb, sig);
521 }
522
523 void
524 mono_mb_emit_icall (MonoMethodBuilder *mb, gpointer func)
525 {
526         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
527         mono_mb_emit_op (mb, CEE_MONO_ICALL, func);
528 }
529
530 void
531 mono_mb_emit_exception_full (MonoMethodBuilder *mb, const char *exc_nspace, const char *exc_name, const char *msg)
532 {
533         MonoMethod *ctor = NULL;
534
535         MonoClass *mme = mono_class_from_name (mono_defaults.corlib, exc_nspace, exc_name);
536         mono_class_init (mme);
537         ctor = mono_class_get_method_from_name (mme, ".ctor", 0);
538         g_assert (ctor);
539         mono_mb_emit_op (mb, CEE_NEWOBJ, ctor);
540         if (msg != NULL) {
541                 mono_mb_emit_byte (mb, CEE_DUP);
542                 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoException, message));
543                 mono_mb_emit_ldstr (mb, (char*)msg);
544                 mono_mb_emit_byte (mb, CEE_STIND_REF);
545         }
546         mono_mb_emit_byte (mb, CEE_THROW);
547 }
548
549 void
550 mono_mb_emit_exception (MonoMethodBuilder *mb, const char *exc_name, const char *msg)
551 {
552         mono_mb_emit_exception_full (mb, "System", exc_name, msg);
553 }
554
555 void
556 mono_mb_emit_add_to_local (MonoMethodBuilder *mb, guint16 local, gint32 incr)
557 {
558         mono_mb_emit_ldloc (mb, local); 
559         mono_mb_emit_icon (mb, incr);
560         mono_mb_emit_byte (mb, CEE_ADD);
561         mono_mb_emit_stloc (mb, local); 
562 }
563
564 void
565 mono_mb_set_clauses (MonoMethodBuilder *mb, int num_clauses, MonoExceptionClause *clauses)
566 {
567         mb->num_clauses = num_clauses;
568         mb->clauses = clauses;
569 }
570
571 /*
572  * mono_mb_set_param_names:
573  *
574  *   PARAM_NAMES should have length equal to the sig->param_count, the caller retains
575  * ownership of the array, and its entries.
576  */
577 void
578 mono_mb_set_param_names (MonoMethodBuilder *mb, const char **param_names)
579 {
580         mb->param_names = param_names;
581 }
582
583 #endif /* DISABLE_JIT */