[runtime] Don't insta-fail when a faulty COM type is encountered. (#5616)
[mono.git] / mono / metadata / method-builder.c
1 /**
2  * \file
3  * Functions for creating IL methods at runtime.
4  * 
5  * Author:
6  *   Paolo Molaro (lupus@ximian.com)
7  *
8  * Copyright 2002-2003 Ximian, Inc (http://www.ximian.com)
9  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
10  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
11  */
12
13 #include "config.h"
14 #include "loader.h"
15 #include "mono/metadata/abi-details.h"
16 #include "mono/metadata/method-builder.h"
17 #include "mono/metadata/tabledefs.h"
18 #include "mono/metadata/exception.h"
19 #include "mono/metadata/appdomain.h"
20 #include "mono/metadata/debug-helpers.h"
21 #include "mono/metadata/metadata-internals.h"
22 #include "mono/metadata/domain-internals.h"
23 #include <string.h>
24 #include <errno.h>
25
26 /* #define DEBUG_RUNTIME_CODE */
27
28 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
29         a = i,
30
31 enum {
32 #include "mono/cil/opcode.def"
33         LAST = 0xff
34 };
35 #undef OPDEF
36
37 #ifdef DEBUG_RUNTIME_CODE
38 static char*
39 indenter (MonoDisHelper *dh, MonoMethod *method, guint32 ip_offset)
40 {
41         return g_strdup (" ");
42 }
43
44 static MonoDisHelper marshal_dh = {
45         "\n",
46         "IL_%04x: ",
47         "IL_%04x",
48         indenter, 
49         NULL,
50         NULL
51 };
52 #endif 
53
54 static MonoMethodBuilder *
55 mono_mb_new_base (MonoClass *klass, MonoWrapperType type)
56 {
57         MonoMethodBuilder *mb;
58         MonoMethod *m;
59
60         g_assert (klass != NULL);
61
62         mb = g_new0 (MonoMethodBuilder, 1);
63
64         mb->method = m = (MonoMethod *)g_new0 (MonoMethodWrapper, 1);
65
66         m->klass = klass;
67         m->inline_info = 1;
68         m->wrapper_type = type;
69
70 #ifdef ENABLE_ILGEN
71         mb->code_size = 40;
72         mb->code = (unsigned char *)g_malloc (mb->code_size);
73         mb->init_locals = TRUE;
74 #endif
75         /* placeholder for the wrapper always at index 1 */
76         mono_mb_add_data (mb, NULL);
77
78         return mb;
79 }
80
81 MonoMethodBuilder *
82 mono_mb_new_no_dup_name (MonoClass *klass, const char *name, MonoWrapperType type)
83 {
84         MonoMethodBuilder *mb = mono_mb_new_base (klass, type);
85         mb->name = (char*)name;
86         mb->no_dup_name = TRUE;
87         return mb;
88 }
89
90 /**
91  * mono_mb_new:
92  */
93 MonoMethodBuilder *
94 mono_mb_new (MonoClass *klass, const char *name, MonoWrapperType type)
95 {
96         MonoMethodBuilder *mb = mono_mb_new_base (klass, type);
97         mb->name = g_strdup (name);
98         return mb;
99 }
100
101 /**
102  * mono_mb_free:
103  */
104 void
105 mono_mb_free (MonoMethodBuilder *mb)
106 {
107 #ifdef ENABLE_ILGEN
108         GList *l;
109
110         for (l = mb->locals_list; l; l = l->next) {
111                 /* Allocated in mono_mb_add_local () */
112                 g_free (l->data);
113         }
114         g_list_free (mb->locals_list);
115         if (!mb->dynamic) {
116                 g_free (mb->method);
117                 if (!mb->no_dup_name)
118                         g_free (mb->name);
119                 g_free (mb->code);
120         }
121 #else
122         g_free (mb->method);
123         if (!mb->no_dup_name)
124                 g_free (mb->name);
125 #endif
126         g_free (mb);
127 }
128
129 /**
130  * mono_mb_create_method:
131  * Create a \c MonoMethod from this method builder.
132  * \returns the newly created method.
133  */
134 MonoMethod *
135 mono_mb_create_method (MonoMethodBuilder *mb, MonoMethodSignature *signature, int max_stack)
136 {
137 #ifdef ENABLE_ILGEN
138         MonoMethodHeader *header;
139 #endif
140         MonoMethodWrapper *mw;
141         MonoImage *image;
142         MonoMethod *method;
143         GList *l;
144         int i;
145
146         g_assert (mb != NULL);
147
148         image = mb->method->klass->image;
149
150 #ifdef ENABLE_ILGEN
151         if (mb->dynamic) {
152                 method = mb->method;
153                 mw = (MonoMethodWrapper*)method;
154
155                 method->name = mb->name;
156                 method->dynamic = TRUE;
157
158                 mw->header = header = (MonoMethodHeader *) 
159                         g_malloc0 (MONO_SIZEOF_METHOD_HEADER + mb->locals * sizeof (MonoType *));
160
161                 header->code = mb->code;
162
163                 for (i = 0, l = mb->locals_list; l; l = l->next, i++) {
164                         header->locals [i] = (MonoType*)l->data;
165                 }
166         } else
167 #endif
168         {
169                 /* Realloc the method info into a mempool */
170
171                 method = (MonoMethod *)mono_image_alloc0 (image, sizeof (MonoMethodWrapper));
172                 memcpy (method, mb->method, sizeof (MonoMethodWrapper));
173                 mw = (MonoMethodWrapper*) method;
174
175                 if (mb->no_dup_name)
176                         method->name = mb->name;
177                 else
178                         method->name = mono_image_strdup (image, mb->name);
179
180 #ifdef ENABLE_ILGEN
181                 mw->header = header = (MonoMethodHeader *) 
182                         mono_image_alloc0 (image, MONO_SIZEOF_METHOD_HEADER + mb->locals * sizeof (MonoType *));
183
184                 header->code = (const unsigned char *)mono_image_alloc (image, mb->pos);
185                 memcpy ((char*)header->code, mb->code, mb->pos);
186
187                 for (i = 0, l = mb->locals_list; l; l = l->next, i++) {
188                         header->locals [i] = (MonoType*)l->data;
189                 }
190 #endif
191         }
192
193 #ifdef ENABLE_ILGEN
194         /* Free the locals list so mono_mb_free () doesn't free the types twice */
195         g_list_free (mb->locals_list);
196         mb->locals_list = NULL;
197 #endif
198
199         method->signature = signature;
200         if (!signature->hasthis)
201                 method->flags |= METHOD_ATTRIBUTE_STATIC;
202
203 #ifdef ENABLE_ILGEN
204         if (max_stack < 8)
205                 max_stack = 8;
206
207         header->max_stack = max_stack;
208
209         header->code_size = mb->pos;
210         header->num_locals = mb->locals;
211         header->init_locals = mb->init_locals;
212
213         header->num_clauses = mb->num_clauses;
214         header->clauses = mb->clauses;
215
216         method->skip_visibility = mb->skip_visibility;
217 #endif
218
219         i = g_list_length ((GList *)mw->method_data);
220         if (i) {
221                 GList *tmp;
222                 void **data;
223                 l = g_list_reverse ((GList *)mw->method_data);
224                 if (method_is_dynamic (method))
225                         data = (void **)g_malloc (sizeof (gpointer) * (i + 1));
226                 else
227                         data = (void **)mono_image_alloc (image, sizeof (gpointer) * (i + 1));
228                 /* store the size in the first element */
229                 data [0] = GUINT_TO_POINTER (i);
230                 i = 1;
231                 for (tmp = l; tmp; tmp = tmp->next) {
232                         data [i++] = tmp->data;
233                 }
234                 g_list_free (l);
235
236                 mw->method_data = data;
237         }
238
239 #ifdef ENABLE_ILGEN
240         /*{
241                 static int total_code = 0;
242                 static int total_alloc = 0;
243                 total_code += mb->pos;
244                 total_alloc += mb->code_size;
245                 g_print ("code size: %d of %d (allocated: %d)\n", mb->pos, total_code, total_alloc);
246         }*/
247
248 #ifdef DEBUG_RUNTIME_CODE
249         printf ("RUNTIME CODE FOR %s\n", mono_method_full_name (method, TRUE));
250         printf ("%s\n", mono_disasm_code (&marshal_dh, method, mb->code, mb->code + mb->pos));
251 #endif
252
253         if (mb->param_names) {
254                 char **param_names = (char **)mono_image_alloc0 (image, signature->param_count * sizeof (gpointer));
255                 for (i = 0; i < signature->param_count; ++i)
256                         param_names [i] = mono_image_strdup (image, mb->param_names [i]);
257
258                 mono_image_lock (image);
259                 if (!image->wrapper_param_names)
260                         image->wrapper_param_names = g_hash_table_new (NULL, NULL);
261                 g_hash_table_insert (image->wrapper_param_names, method, param_names);
262                 mono_image_unlock (image);
263         }
264 #endif
265
266         return method;
267 }
268
269 /**
270  * mono_mb_add_data:
271  */
272 guint32
273 mono_mb_add_data (MonoMethodBuilder *mb, gpointer data)
274 {
275         MonoMethodWrapper *mw;
276
277         g_assert (mb != NULL);
278
279         mw = (MonoMethodWrapper *)mb->method;
280
281         /* one O(n) is enough */
282         mw->method_data = g_list_prepend ((GList *)mw->method_data, data);
283
284         return g_list_length ((GList *)mw->method_data);
285 }
286
287 #ifdef ENABLE_ILGEN
288
289 /**
290  * mono_mb_add_local:
291  */
292 int
293 mono_mb_add_local (MonoMethodBuilder *mb, MonoType *type)
294 {
295         int res;
296         MonoType *t;
297
298         /*
299          * Have to make a copy early since type might be sig->ret,
300          * which is transient, see mono_metadata_signature_dup_internal_with_padding ().
301          */
302         t = mono_metadata_type_dup (NULL, type);
303
304         g_assert (mb != NULL);
305         g_assert (type != NULL);
306
307         res = mb->locals;
308         mb->locals_list = g_list_append (mb->locals_list, t);
309         mb->locals++;
310
311         return res;
312 }
313
314 /**
315  * mono_mb_patch_addr:
316  */
317 void
318 mono_mb_patch_addr (MonoMethodBuilder *mb, int pos, int value)
319 {
320         mb->code [pos] = value & 0xff;
321         mb->code [pos + 1] = (value >> 8) & 0xff;
322         mb->code [pos + 2] = (value >> 16) & 0xff;
323         mb->code [pos + 3] = (value >> 24) & 0xff;
324 }
325
326 /**
327  * mono_mb_patch_addr_s:
328  */
329 void
330 mono_mb_patch_addr_s (MonoMethodBuilder *mb, int pos, gint8 value)
331 {
332         *((gint8 *)(&mb->code [pos])) = value;
333 }
334
335 /**
336  * mono_mb_emit_byte:
337  */
338 void
339 mono_mb_emit_byte (MonoMethodBuilder *mb, guint8 op)
340 {
341         if (mb->pos >= mb->code_size) {
342                 mb->code_size += mb->code_size >> 1;
343                 mb->code = (unsigned char *)g_realloc (mb->code, mb->code_size);
344         }
345
346         mb->code [mb->pos++] = op;
347 }
348
349 /**
350  * mono_mb_emit_ldflda:
351  */
352 void
353 mono_mb_emit_ldflda (MonoMethodBuilder *mb, gint32 offset)
354 {
355         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
356         mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
357
358         if (offset) {
359                 mono_mb_emit_icon (mb, offset);
360                 mono_mb_emit_byte (mb, CEE_ADD);
361         }
362 }
363
364 /**
365  * mono_mb_emit_i4:
366  */
367 void
368 mono_mb_emit_i4 (MonoMethodBuilder *mb, gint32 data)
369 {
370         if ((mb->pos + 4) >= mb->code_size) {
371                 mb->code_size += mb->code_size >> 1;
372                 mb->code = (unsigned char *)g_realloc (mb->code, mb->code_size);
373         }
374
375         mono_mb_patch_addr (mb, mb->pos, data);
376         mb->pos += 4;
377 }
378
379 void
380 mono_mb_emit_i8 (MonoMethodBuilder *mb, gint64 data)
381 {
382         if ((mb->pos + 8) >= mb->code_size) {
383                 mb->code_size += mb->code_size >> 1;
384                 mb->code = (unsigned char *)g_realloc (mb->code, mb->code_size);
385         }
386
387         mono_mb_patch_addr (mb, mb->pos, data);
388         mono_mb_patch_addr (mb, mb->pos + 4, data >> 32);
389         mb->pos += 8;
390 }
391
392 /**
393  * mono_mb_emit_i2:
394  */
395 void
396 mono_mb_emit_i2 (MonoMethodBuilder *mb, gint16 data)
397 {
398         if ((mb->pos + 2) >= mb->code_size) {
399                 mb->code_size += mb->code_size >> 1;
400                 mb->code = (unsigned char *)g_realloc (mb->code, mb->code_size);
401         }
402
403         mb->code [mb->pos] = data & 0xff;
404         mb->code [mb->pos + 1] = (data >> 8) & 0xff;
405         mb->pos += 2;
406 }
407
408 void
409 mono_mb_emit_op (MonoMethodBuilder *mb, guint8 op, gpointer data)
410 {
411         mono_mb_emit_byte (mb, op);
412         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, data));
413 }
414
415 /**
416  * mono_mb_emit_ldstr:
417  */
418 void
419 mono_mb_emit_ldstr (MonoMethodBuilder *mb, char *str)
420 {
421         mono_mb_emit_op (mb, CEE_LDSTR, str);
422 }
423
424 /**
425  * mono_mb_emit_ldarg:
426  */
427 void
428 mono_mb_emit_ldarg (MonoMethodBuilder *mb, guint argnum)
429 {
430         if (argnum < 4) {
431                 mono_mb_emit_byte (mb, CEE_LDARG_0 + argnum);
432         } else if (argnum < 256) {
433                 mono_mb_emit_byte (mb, CEE_LDARG_S);
434                 mono_mb_emit_byte (mb, argnum);
435         } else {
436                 mono_mb_emit_byte (mb, CEE_PREFIX1);
437                 mono_mb_emit_byte (mb, CEE_LDARG);
438                 mono_mb_emit_i2 (mb, argnum);
439         }
440 }
441
442 /**
443  * mono_mb_emit_ldarg_addr:
444  */
445 void
446 mono_mb_emit_ldarg_addr (MonoMethodBuilder *mb, guint argnum)
447 {
448         if (argnum < 256) {
449                 mono_mb_emit_byte (mb, CEE_LDARGA_S);
450                 mono_mb_emit_byte (mb, argnum);
451         } else {
452                 mono_mb_emit_byte (mb, CEE_PREFIX1);
453                 mono_mb_emit_byte (mb, CEE_LDARGA);
454                 mono_mb_emit_i2 (mb, argnum);
455         }
456 }
457
458 /**
459  * mono_mb_emit_ldloc_addr:
460  */
461 void
462 mono_mb_emit_ldloc_addr (MonoMethodBuilder *mb, guint locnum)
463 {
464         if (locnum < 256) {
465                 mono_mb_emit_byte (mb, CEE_LDLOCA_S);
466                 mono_mb_emit_byte (mb, locnum);
467         } else {
468                 mono_mb_emit_byte (mb, CEE_PREFIX1);
469                 mono_mb_emit_byte (mb, CEE_LDLOCA);
470                 mono_mb_emit_i2 (mb, locnum);
471         }
472 }
473
474 /**
475  * mono_mb_emit_ldloc:
476  */
477 void
478 mono_mb_emit_ldloc (MonoMethodBuilder *mb, guint num)
479 {
480         if (num < 4) {
481                 mono_mb_emit_byte (mb, CEE_LDLOC_0 + num);
482         } else if (num < 256) {
483                 mono_mb_emit_byte (mb, CEE_LDLOC_S);
484                 mono_mb_emit_byte (mb, num);
485         } else {
486                 mono_mb_emit_byte (mb, CEE_PREFIX1);
487                 mono_mb_emit_byte (mb, CEE_LDLOC);
488                 mono_mb_emit_i2 (mb, num);
489         }
490 }
491
492 /**
493  * mono_mb_emit_stloc:
494  */
495 void
496 mono_mb_emit_stloc (MonoMethodBuilder *mb, guint num)
497 {
498         if (num < 4) {
499                 mono_mb_emit_byte (mb, CEE_STLOC_0 + num);
500         } else if (num < 256) {
501                 mono_mb_emit_byte (mb, CEE_STLOC_S);
502                 mono_mb_emit_byte (mb, num);
503         } else {
504                 mono_mb_emit_byte (mb, CEE_PREFIX1);
505                 mono_mb_emit_byte (mb, CEE_STLOC);
506                 mono_mb_emit_i2 (mb, num);
507         }
508 }
509
510 /**
511  * mono_mb_emit_icon:
512  */
513 void
514 mono_mb_emit_icon (MonoMethodBuilder *mb, gint32 value)
515 {
516         if (value >= -1 && value < 8) {
517                 mono_mb_emit_byte (mb, CEE_LDC_I4_0 + value);
518         } else if (value >= -128 && value <= 127) {
519                 mono_mb_emit_byte (mb, CEE_LDC_I4_S);
520                 mono_mb_emit_byte (mb, value);
521         } else {
522                 mono_mb_emit_byte (mb, CEE_LDC_I4);
523                 mono_mb_emit_i4 (mb, value);
524         }
525 }
526
527 void
528 mono_mb_emit_icon8 (MonoMethodBuilder *mb, gint64 value)
529 {
530         mono_mb_emit_byte (mb, CEE_LDC_I8);
531         mono_mb_emit_i8 (mb, value);
532 }
533
534 int
535 mono_mb_get_label (MonoMethodBuilder *mb)
536 {
537         return mb->pos;
538 }
539
540 int
541 mono_mb_get_pos (MonoMethodBuilder *mb)
542 {
543         return mb->pos;
544 }
545
546 /**
547  * mono_mb_emit_branch:
548  */
549 guint32
550 mono_mb_emit_branch (MonoMethodBuilder *mb, guint8 op)
551 {
552         guint32 res;
553         mono_mb_emit_byte (mb, op);
554         res = mb->pos;
555         mono_mb_emit_i4 (mb, 0);
556         return res;
557 }
558
559 guint32
560 mono_mb_emit_short_branch (MonoMethodBuilder *mb, guint8 op)
561 {
562         guint32 res;
563         mono_mb_emit_byte (mb, op);
564         res = mb->pos;
565         mono_mb_emit_byte (mb, 0);
566
567         return res;
568 }
569
570 void
571 mono_mb_emit_branch_label (MonoMethodBuilder *mb, guint8 op, guint32 label)
572 {
573         mono_mb_emit_byte (mb, op);
574         mono_mb_emit_i4 (mb, label - (mb->pos + 4));
575 }
576
577 void
578 mono_mb_patch_branch (MonoMethodBuilder *mb, guint32 pos)
579 {
580         mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
581 }
582
583 void
584 mono_mb_patch_short_branch (MonoMethodBuilder *mb, guint32 pos)
585 {
586         mono_mb_patch_addr_s (mb, pos, mb->pos - (pos + 1));
587 }
588
589 void
590 mono_mb_emit_ptr (MonoMethodBuilder *mb, gpointer ptr)
591 {
592         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
593         mono_mb_emit_op (mb, CEE_MONO_LDPTR, ptr);
594 }
595
596 void
597 mono_mb_emit_calli (MonoMethodBuilder *mb, MonoMethodSignature *sig)
598 {
599         mono_mb_emit_op (mb, CEE_CALLI, sig);
600 }
601
602 /**
603  * mono_mb_emit_managed_call:
604  */
605 void
606 mono_mb_emit_managed_call (MonoMethodBuilder *mb, MonoMethod *method, MonoMethodSignature *opt_sig)
607 {
608         mono_mb_emit_op (mb, CEE_CALL, method);
609 }
610
611 /**
612  * mono_mb_emit_native_call:
613  */
614 void
615 mono_mb_emit_native_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, gpointer func)
616 {
617         mono_mb_emit_ptr (mb, func);
618         mono_mb_emit_calli (mb, sig);
619 }
620
621 void
622 mono_mb_emit_icall (MonoMethodBuilder *mb, gpointer func)
623 {
624         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
625         mono_mb_emit_op (mb, CEE_MONO_ICALL, func);
626 }
627
628 void
629 mono_mb_emit_exception_full (MonoMethodBuilder *mb, const char *exc_nspace, const char *exc_name, const char *msg)
630 {
631         MonoMethod *ctor = NULL;
632
633         MonoClass *mme = mono_class_load_from_name (mono_defaults.corlib, exc_nspace, exc_name);
634         mono_class_init (mme);
635         ctor = mono_class_get_method_from_name (mme, ".ctor", 0);
636         g_assert (ctor);
637         mono_mb_emit_op (mb, CEE_NEWOBJ, ctor);
638         if (msg != NULL) {
639                 mono_mb_emit_byte (mb, CEE_DUP);
640                 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoException, message));
641                 mono_mb_emit_ldstr (mb, (char*)msg);
642                 mono_mb_emit_byte (mb, CEE_STIND_REF);
643         }
644         mono_mb_emit_byte (mb, CEE_THROW);
645 }
646
647 /**
648  * mono_mb_emit_exception:
649  */
650 void
651 mono_mb_emit_exception (MonoMethodBuilder *mb, const char *exc_name, const char *msg)
652 {
653         mono_mb_emit_exception_full (mb, "System", exc_name, msg);
654 }
655
656 /**
657  * mono_mb_emit_exception_for_error:
658  */
659 void
660 mono_mb_emit_exception_for_error (MonoMethodBuilder *mb, MonoError *error)
661 {
662         /*
663          * If at some point there is need to support other types of errors,
664          * the behaviour should conform with mono_error_prepare_exception().
665          */
666         g_assert (mono_error_get_error_code (error) == MONO_ERROR_GENERIC && "Unsupported error code.");
667         mono_mb_emit_exception_full (mb, "System", mono_error_get_exception_name (error), mono_error_get_message (error));
668 }
669
670 /**
671  * mono_mb_emit_add_to_local:
672  */
673 void
674 mono_mb_emit_add_to_local (MonoMethodBuilder *mb, guint16 local, gint32 incr)
675 {
676         mono_mb_emit_ldloc (mb, local); 
677         mono_mb_emit_icon (mb, incr);
678         mono_mb_emit_byte (mb, CEE_ADD);
679         mono_mb_emit_stloc (mb, local); 
680 }
681
682 void
683 mono_mb_set_clauses (MonoMethodBuilder *mb, int num_clauses, MonoExceptionClause *clauses)
684 {
685         mb->num_clauses = num_clauses;
686         mb->clauses = clauses;
687 }
688
689 /*
690  * mono_mb_set_param_names:
691  *
692  *   PARAM_NAMES should have length equal to the sig->param_count, the caller retains
693  * ownership of the array, and its entries.
694  */
695 void
696 mono_mb_set_param_names (MonoMethodBuilder *mb, const char **param_names)
697 {
698         mb->param_names = param_names;
699 }
700
701 #endif /* DISABLE_JIT */