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