2 * jit.c: The mono JIT compiler.
5 * Dietmar Maurer (dietmar@ximian.com)
7 * (C) 2001 Ximian, Inc.
20 #include <mono/metadata/verify.h>
21 #include <mono/metadata/assembly.h>
22 #include <mono/metadata/loader.h>
23 #include <mono/metadata/cil-coff.h>
24 #include <mono/metadata/tabledefs.h>
25 #include <mono/metadata/class.h>
26 #include <mono/metadata/object.h>
27 #include <mono/metadata/debug-helpers.h>
28 #include <mono/metadata/opcodes.h>
29 #include <mono/metadata/mono-endian.h>
30 #include <mono/metadata/tokentype.h>
31 #include <mono/metadata/threads.h>
32 #include <mono/metadata/socket-io.h>
33 #include <mono/metadata/appdomain.h>
34 #include <mono/arch/x86/x86-codegen.h>
35 #include <mono/io-layer/io-layer.h>
36 #include <mono/io-layer/threads.h>
44 * if OPT_BOOL is defined we use 32bit to store boolean local variables. This
45 * gives great speedup for boolean expressions, but unfortunately it changes
46 * semantics, so i disable it until we have a real solution */
47 /* #define OPT_BOOL */
49 /* this is x86 specific */
50 #define MB_TERM_LDIND_REF MB_TERM_LDIND_I4
51 #define MB_TERM_LDIND_U4 MB_TERM_LDIND_I4
52 #define MB_TERM_STIND_REF MB_TERM_STIND_I4
53 #define MB_TERM_REMOTE_STIND_REF MB_TERM_REMOTE_STIND_I4
55 #define SET_VARINFO(vi,t,k,o,s) do { vi.type=t; vi.kind=k; vi.offset=o; vi.size=s; } while (0)
57 #define MAKE_CJUMP(name) \
59 case CEE_##name##_S: { \
61 int near_jump = *ip == CEE_##name##_S; \
64 t1 = mono_ctree_new (mp, MB_TERM_COMPARE, sp [0], sp [1]); \
65 t1 = mono_ctree_new (mp, MB_TERM_CBRANCH, t1, NULL); \
67 target = cli_addr + 2 + (signed char) *ip; \
69 target = cli_addr + 5 + (gint32) read32 (ip); \
70 g_assert (target >= 0 && target <= header->code_size); \
71 g_assert (bcinfo [target].is_block_start); \
72 tbb = &cfg->bblocks [bcinfo [target].block_id]; \
73 create_outstack (cfg, bb, stack, sp - stack); \
74 mark_reached (cfg, tbb, bb->outstack, bb->outdepth); \
75 t1->data.bi.target = tbb; \
76 t1->data.bi.cond = CEE_##name; \
77 ADD_TREE (t1, cli_addr); \
78 ip += near_jump ? 1: 4; \
82 #define MAKE_BI_ALU(name) \
86 t1 = mono_ctree_new (mp, MB_TERM_##name, sp [0], sp [1]); \
87 PUSH_TREE (t1, sp [0]->svt); \
91 #define MAKE_CMP(cname) \
95 t1 = mono_ctree_new (mp, MB_TERM_COMPARE, sp [0], sp [1]); \
96 t1 = mono_ctree_new (mp, MB_TERM_CSET, t1, NULL); \
97 t1->data.i = CEE_##cname; \
98 PUSH_TREE (t1, VAL_I32); \
102 #define MAKE_SPILLED_BI_ALU(name) \
106 t1 = mono_ctree_new (mp, MB_TERM_##name, sp [0], sp [1]); \
107 t1->svt = sp [0]->svt; \
108 t1 = mono_store_tree (cfg, -1, t1, &t2); \
110 ADD_TREE (t1, cli_addr); \
111 PUSH_TREE (t2, t2->svt); \
115 #define MAKE_LDIND(name, op, svt) \
119 t1 = mono_ctree_new (mp, op, *sp, NULL); \
120 PUSH_TREE (t1, svt); \
124 #define MAKE_LDELEM(name, op, svt, s) \
128 t1 = mono_ctree_new (mp, MB_TERM_LDELEMA, sp [0], sp [1]); \
130 t1 = mono_ctree_new (mp, op, t1, NULL); \
131 PUSH_TREE (t1, svt); \
135 #define MAKE_LDELEM_OLD(name, op, svt, s) \
139 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4); \
141 t1 = mono_ctree_new (mp, MB_TERM_MUL, sp [1], t1); \
142 t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4); \
143 t2->data.i = G_STRUCT_OFFSET (MonoArray, vector); \
144 t2 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], t2); \
145 t1 = mono_ctree_new (mp, MB_TERM_ADD, t1, t2); \
146 t1 = mono_ctree_new (mp, op, t1, NULL); \
147 PUSH_TREE (t1, svt); \
151 #define MAKE_STIND(name, op) \
155 t1 = mono_ctree_new (mp, op, sp [0], sp [1]); \
156 ADD_TREE (t1, cli_addr); \
160 #define MAKE_STELEM(name, op, s) \
164 t1 = mono_ctree_new (mp, MB_TERM_LDELEMA, sp [0], sp [1]); \
166 t1 = mono_ctree_new (mp, op, t1, sp [2]); \
167 ADD_TREE (t1, cli_addr); \
171 #define MAKE_STELEM_OLD(name, op, s) \
175 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4); \
177 t1 = mono_ctree_new (mp, MB_TERM_MUL, sp [1], t1); \
178 t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4); \
179 t2->data.i = G_STRUCT_OFFSET (MonoArray, vector); \
180 t2 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], t2); \
181 t1 = mono_ctree_new (mp, MB_TERM_ADD, t1, t2); \
182 t1 = mono_ctree_new (mp, op, t1, sp [2]); \
183 ADD_TREE (t1, cli_addr); \
190 const unsigned char *end, *saved_ip;
191 MonoImage *saved_image;
194 /* Whether to dump the assembly code after genreating it */
195 gboolean mono_jit_dump_asm = FALSE;
197 /* Whether to dump the forest */
198 gboolean mono_jit_dump_forest = FALSE;
200 /* Whether to print function call traces */
201 gboolean mono_jit_trace_calls = FALSE;
203 /* Whether to insert in the code profile callbacks */
204 gboolean mono_jit_profile = FALSE;
206 /* Force jit to share code between application domains */
207 gboolean mono_jit_share_code = FALSE;
209 /* use linear scan register allocation */
210 gboolean mono_use_linear_scan = TRUE;
213 gboolean mono_jit_inline_code = TRUE;
215 /* Use alternative (faster) sequence to convert FP values to integers */
216 gboolean mono_use_fast_iconv = FALSE;
218 /* maximum number of worker threads */
219 int mono_worker_threads = 1;
221 /* TLS id to store jit data */
222 guint32 mono_jit_tls_id;
224 MonoDebugHandle *mono_debug_handle = NULL;
225 GList *mono_debug_methods = NULL;
227 /* If non-zero, insert a breakpoint when compiling the next method.
228 * If positive, interpret this variable as a counter and decrement
229 * it after setting the breakpoint. */
230 int mono_debug_insert_breakpoint = 0;
232 /* This is the address of the last breakpoint which was inserted. */
233 gchar *mono_debug_last_breakpoint_address = NULL;
235 MonoJitStats mono_jit_stats;
237 CRITICAL_SECTION *metadata_section = NULL;
240 * We sometimes need static data, for example the forest generator need it to
241 * store constants or class data.
243 inline static gpointer
244 mono_alloc_static (int size)
246 return g_malloc (size);
248 inline static gpointer
249 mono_alloc_static0 (int size)
251 return g_malloc0 (size);
254 typedef void (*MonoCCtor) (void);
258 map_store_svt_type (int svt)
262 return MB_TERM_STIND_I4;
264 return MB_TERM_STIND_REF;
266 return MB_TERM_STIND_I8;
268 return MB_TERM_STIND_R8;
270 g_assert_not_reached ();
278 * @type: the type to map
280 * Translates the MonoType @type into the corresponding store opcode
281 * for the code generator.
284 map_stind_type (MonoType *type)
287 return MB_TERM_STIND_REF;
289 switch (type->type) {
292 case MONO_TYPE_BOOLEAN:
293 return MB_TERM_STIND_I1;
297 return MB_TERM_STIND_I2;
301 return MB_TERM_STIND_I4;
302 case MONO_TYPE_CLASS:
303 case MONO_TYPE_OBJECT:
304 case MONO_TYPE_STRING:
306 case MONO_TYPE_SZARRAY:
307 case MONO_TYPE_ARRAY:
308 return MB_TERM_STIND_REF;
311 return MB_TERM_STIND_I8;
313 return MB_TERM_STIND_R4;
315 return MB_TERM_STIND_R8;
316 case MONO_TYPE_VALUETYPE:
317 if (type->data.klass->enumtype)
318 return map_stind_type (type->data.klass->enum_basetype);
320 return MB_TERM_STIND_OBJ;
322 g_warning ("unknown type %02x", type->type);
323 g_assert_not_reached ();
326 g_assert_not_reached ();
331 * map_remote_stind_type:
332 * @type: the type to map
334 * Translates the MonoType @type into the corresponding remote store opcode
335 * for the code generator.
338 map_remote_stind_type (MonoType *type)
341 return MB_TERM_REMOTE_STIND_REF;
344 switch (type->type) {
347 case MONO_TYPE_BOOLEAN:
348 return MB_TERM_REMOTE_STIND_I1;
352 return MB_TERM_REMOTE_STIND_I2;
356 return MB_TERM_REMOTE_STIND_I4;
357 case MONO_TYPE_CLASS:
358 case MONO_TYPE_OBJECT:
359 case MONO_TYPE_STRING:
361 case MONO_TYPE_SZARRAY:
362 case MONO_TYPE_ARRAY:
363 return MB_TERM_REMOTE_STIND_REF;
366 return MB_TERM_REMOTE_STIND_I8;
368 return MB_TERM_REMOTE_STIND_R4;
370 return MB_TERM_REMOTE_STIND_R8;
371 case MONO_TYPE_VALUETYPE:
372 if (type->data.klass->enumtype)
373 return map_remote_stind_type (type->data.klass->enum_basetype);
375 return MB_TERM_REMOTE_STIND_OBJ;
377 g_warning ("unknown type %02x", type->type);
378 g_assert_not_reached ();
381 g_assert_not_reached ();
386 map_starg_type (MonoType *type)
389 return MB_TERM_STIND_REF;
391 switch (type->type) {
394 case MONO_TYPE_BOOLEAN:
401 return MB_TERM_STIND_I4;
402 case MONO_TYPE_CLASS:
403 case MONO_TYPE_OBJECT:
404 case MONO_TYPE_STRING:
406 case MONO_TYPE_SZARRAY:
407 case MONO_TYPE_ARRAY:
408 return MB_TERM_STIND_REF;
411 return MB_TERM_STIND_I8;
413 return MB_TERM_STIND_R4;
415 return MB_TERM_STIND_R8;
416 case MONO_TYPE_VALUETYPE:
417 if (type->data.klass->enumtype)
418 return map_starg_type (type->data.klass->enum_basetype);
420 return MB_TERM_STIND_OBJ;
422 g_warning ("unknown type %02x", type->type);
423 g_assert_not_reached ();
426 g_assert_not_reached ();
431 map_arg_type (MonoType *type)
434 return MB_TERM_ARG_I4;
436 switch (type->type) {
439 case MONO_TYPE_BOOLEAN:
447 case MONO_TYPE_CLASS:
448 case MONO_TYPE_OBJECT:
450 case MONO_TYPE_SZARRAY:
451 case MONO_TYPE_ARRAY:
452 return MB_TERM_ARG_I4;
453 case MONO_TYPE_STRING:
454 return MB_TERM_ARG_I4;
457 return MB_TERM_ARG_I8;
459 return MB_TERM_ARG_R4;
461 return MB_TERM_ARG_R8;
462 case MONO_TYPE_VALUETYPE:
463 if (type->data.klass->enumtype)
464 return map_arg_type (type->data.klass->enum_basetype);
466 return MB_TERM_ARG_OBJ;
468 g_warning ("unknown type %02x", type->type);
469 g_assert_not_reached ();
472 g_assert_not_reached ();
478 * @type: the type to map
480 * Translates the MonoType @type into the corresponding load opcode
481 * for the code generator.
484 map_ldind_type (MonoType *type, MonoValueType *svt)
488 return MB_TERM_LDIND_REF;
491 switch (type->type) {
494 return MB_TERM_LDIND_I1;
496 case MONO_TYPE_BOOLEAN:
498 return MB_TERM_LDIND_U1;
501 return MB_TERM_LDIND_I2;
505 return MB_TERM_LDIND_U2;
509 return MB_TERM_LDIND_I4;
512 return MB_TERM_LDIND_U4;
513 case MONO_TYPE_CLASS:
514 case MONO_TYPE_OBJECT:
515 case MONO_TYPE_STRING:
517 case MONO_TYPE_SZARRAY:
518 case MONO_TYPE_ARRAY:
520 return MB_TERM_LDIND_REF;
524 return MB_TERM_LDIND_I8;
527 return MB_TERM_LDIND_R4;
530 return MB_TERM_LDIND_R8;
531 case MONO_TYPE_VALUETYPE:
532 if (type->data.klass->enumtype) {
533 return map_ldind_type (type->data.klass->enum_basetype, svt);
536 return MB_TERM_LDIND_OBJ;
539 g_warning ("unknown type %02x", type->type);
540 g_assert_not_reached ();
543 g_assert_not_reached ();
548 map_ldarg_type (MonoType *type, MonoValueType *svt)
552 return MB_TERM_LDIND_REF;
555 switch (type->type) {
558 case MONO_TYPE_BOOLEAN:
566 return MB_TERM_LDIND_U4;
567 case MONO_TYPE_CLASS:
568 case MONO_TYPE_OBJECT:
569 case MONO_TYPE_STRING:
571 case MONO_TYPE_SZARRAY:
572 case MONO_TYPE_ARRAY:
574 return MB_TERM_LDIND_U4;
578 return MB_TERM_LDIND_I8;
581 return MB_TERM_LDIND_R4;
584 return MB_TERM_LDIND_R8;
585 case MONO_TYPE_VALUETYPE:
586 if (type->data.klass->enumtype) {
587 return map_ldarg_type (type->data.klass->enum_basetype, svt);
590 return MB_TERM_LDIND_OBJ;
593 g_warning ("unknown type %02x", type->type);
594 g_assert_not_reached ();
597 g_assert_not_reached ();
603 * @type: the type to map
605 * Translates the MonoType @type into the corresponding call opcode
606 * for the code generator.
609 map_call_type (MonoType *type, MonoValueType *svt)
612 return MB_TERM_CALL_I4;
614 switch (type->type) {
617 return MB_TERM_CALL_VOID;
620 case MONO_TYPE_BOOLEAN:
628 return MB_TERM_CALL_I4;
629 case MONO_TYPE_VALUETYPE:
630 if (type->data.klass->enumtype) {
631 return map_call_type (type->data.klass->enum_basetype, svt);
634 return MB_TERM_CALL_VOID;
636 case MONO_TYPE_CLASS:
637 case MONO_TYPE_OBJECT:
638 case MONO_TYPE_STRING:
640 case MONO_TYPE_SZARRAY:
642 return MB_TERM_CALL_I4;
646 return MB_TERM_CALL_I8;
650 return MB_TERM_CALL_R8;
652 g_warning ("unknown type %02x", type->type);
653 g_assert_not_reached ();
656 g_assert_not_reached ();
661 * prints the tree to stdout
664 mono_print_ctree (MonoFlowGraph *cfg, MBTree *tree)
671 arity = (tree->left != NULL) + (tree->right != NULL);
674 printf (" (%s", mono_burg_term_string [tree->op]);
676 printf (" %s", mono_burg_term_string [tree->op]);
679 case MB_TERM_CONST_I4:
680 printf ("[%d]", tree->data.i);
683 if (VARINFO (cfg, tree->data.i).reg >= 0)
684 printf ("[R%d]", tree->data.i);
686 printf ("[%d]", tree->data.i);
690 g_assert (!(tree->right && !tree->left));
692 mono_print_ctree (cfg, tree->left);
693 mono_print_ctree (cfg, tree->right);
700 * prints the whole forest to stdout
703 mono_print_forest (MonoFlowGraph *cfg, GPtrArray *forest)
705 const int top = forest->len;
708 for (i = 0; i < top; i++) {
709 MBTree *t = (MBTree *) g_ptr_array_index (forest, i);
711 mono_print_ctree (cfg, t);
718 * mono_disassemble_code:
719 * @code: a pointer to the code
720 * @size: the code size in bytes
722 * Disassemble to code to stdout.
725 mono_disassemble_code (guint8 *code, int size, char *id)
730 if (!(ofd = fopen ("/tmp/test.s", "w")))
731 g_assert_not_reached ();
733 fprintf (ofd, "%s:\n", id);
735 for (i = 0; i < size; ++i)
736 fprintf (ofd, ".byte %d\n", (unsigned int) code [i]);
740 system ("as /tmp/test.s -o /tmp/test.o;objdump -d /tmp/test.o");
744 arch_allocate_var (MonoFlowGraph *cfg, int size, int align, MonoValueKind kind, MonoValueType type)
748 mono_jit_stats.allocate_var++;
750 vi.range.last_use.abs_pos = 0;
751 vi.range.first_use.pos.bid = 0xffff;
752 vi.range.first_use.pos.tid = 0;
755 vi.varnum = cfg->varinfo->len;
757 if (size != sizeof (gpointer))
762 case MONO_LOCALVAR: {
763 cfg->locals_size += size;
764 cfg->locals_size += align - 1;
765 cfg->locals_size &= ~(align - 1);
767 SET_VARINFO (vi, type, kind, - cfg->locals_size, size);
768 g_array_append_val (cfg->varinfo, vi);
772 int arg_start = 8 + cfg->has_vtarg*4;
774 g_assert ((align & 3) == 0);
776 SET_VARINFO (vi, type, kind, cfg->args_size + arg_start, size);
777 g_array_append_val (cfg->varinfo, vi);
779 cfg->args_size += size;
781 cfg->args_size &= ~3;
785 g_assert_not_reached ();
788 return cfg->varinfo->len - 1;
792 mono_get_val_sizes (MonoValueType type, int *size, int *align)
796 *size = *align = sizeof (gint32);
799 *size = *align = sizeof (gint64);
802 *size = *align = sizeof (gpointer);
805 *size = *align = sizeof (double);
808 g_assert_not_reached ();
813 mono_allocate_intvar (MonoFlowGraph *cfg, int slot, MonoValueType type)
815 int size, align, vnum, pos;
817 g_assert (type != VAL_UNKNOWN);
819 /* take care if you modify MonoValueType */
820 g_assert (VAL_DOUBLE == 4);
822 /* fixme: machine dependant */
823 if (type == VAL_POINTER)
824 type = VAL_I32; /* VAL_I32 and VAL_POINTER share the same slot */
826 pos = type - 1 + slot * VAL_DOUBLE;
828 if ((vnum = cfg->intvars [pos]))
830 mono_get_val_sizes (type, &size, &align);
832 cfg->intvars[pos] = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, type);
834 return cfg->intvars[pos];
838 mono_allocate_excvar (MonoFlowGraph *cfg)
843 cfg->excvar = arch_allocate_var (cfg, 4, 4, MONO_TEMPVAR, VAL_POINTER);
851 * @cfg: pointer to the control flow graph
852 * @type: the type of the value to load
853 * @addr: the address of the value
855 * Creates a tree to load the value at address @addr.
857 inline static MBTree *
858 ctree_create_load (MonoFlowGraph *cfg, MonoType *type, MBTree *addr, MonoValueType *svt, gboolean arg)
860 MonoMemPool *mp = cfg->mp;
865 ldind = map_ldarg_type (type, svt);
867 ldind = map_ldind_type (type, svt);
869 t = mono_ctree_new (mp, ldind, addr, NULL);
875 * ctree_create_store:
876 * @mp: pointer to a memory pool
877 * @addr_type: address type (MB_TERM_ADDR_L or MB_TERM_ADDR_G)
878 * @s: the value (tree) to store
879 * @type: the type of the value
880 * @addr: the address of the value
882 * Creates a tree to store the value @s at address @addr.
884 inline static MBTree *
885 ctree_create_store (MonoFlowGraph *cfg, MonoType *type, MBTree *addr,
886 MBTree *s, gboolean arg)
888 MonoMemPool *mp = cfg->mp;
893 stind = map_starg_type (type);
895 stind = map_stind_type (type);
897 t = mono_ctree_new (mp, stind, addr, s);
900 t->data.i = mono_class_value_size (type->data.klass, NULL);
905 inline static MBTree *
906 ctree_dup_address (MonoMemPool *mp, MBTree *s)
914 t = mono_ctree_new_leaf (mp, s->op);
915 t->data.i = s->data.i;
916 t->svt = VAL_POINTER;
919 g_warning ("unknown tree opcode %d", s->op);
920 g_assert_not_reached ();
927 * Create a duplicate of the value of a tree. This is
928 * easy for trees starting with LDIND/STIND, since the
929 * duplicate is simple a LDIND tree with the same address.
930 * For other trees we have to split the tree into one tree
931 * storing the value to a new temporary variable, and
932 * another tree which loads that value back. We can then
933 * duplicate the second tree.
936 ctree_create_dup (MonoMemPool *mp, MBTree *s)
941 case MB_TERM_STIND_I1:
942 case MB_TERM_LDIND_I1:
943 t = ctree_dup_address (mp, s->left);
944 t = mono_ctree_new (mp, MB_TERM_LDIND_I1, t, NULL);
947 case MB_TERM_STIND_I2:
948 case MB_TERM_LDIND_I2:
949 t = ctree_dup_address (mp, s->left);
950 t = mono_ctree_new (mp, MB_TERM_LDIND_I2, t, NULL);
953 case MB_TERM_STIND_I4:
954 case MB_TERM_LDIND_I4:
955 t = ctree_dup_address (mp, s->left);
956 t = mono_ctree_new (mp, MB_TERM_LDIND_I4, t, NULL);
959 case MB_TERM_STIND_I8:
960 case MB_TERM_LDIND_I8:
961 t = ctree_dup_address (mp, s->left);
962 t = mono_ctree_new (mp, MB_TERM_LDIND_I8, t, NULL);
965 case MB_TERM_STIND_R4:
966 case MB_TERM_LDIND_R4:
967 t = ctree_dup_address (mp, s->left);
968 t = mono_ctree_new (mp, MB_TERM_LDIND_R4, t, NULL);
971 case MB_TERM_STIND_R8:
972 case MB_TERM_LDIND_R8:
973 t = ctree_dup_address (mp, s->left);
974 t = mono_ctree_new (mp, MB_TERM_LDIND_R8, t, NULL);
978 g_warning ("unknown op \"%s\"", mono_burg_term_string [s->op]);
979 g_assert_not_reached ();
986 mono_store_tree (MonoFlowGraph *cfg, int slot, MBTree *s, MBTree **tdup)
988 MonoMemPool *mp = cfg->mp;
993 case MB_TERM_STIND_I1:
994 case MB_TERM_LDIND_I1:
995 case MB_TERM_STIND_I2:
996 case MB_TERM_LDIND_I2:
997 case MB_TERM_STIND_I4:
998 case MB_TERM_LDIND_I4:
999 case MB_TERM_STIND_I8:
1000 case MB_TERM_LDIND_I8:
1001 case MB_TERM_STIND_R4:
1002 case MB_TERM_LDIND_R4:
1003 case MB_TERM_STIND_R8:
1004 case MB_TERM_LDIND_R8: {
1006 vnum = mono_allocate_intvar (cfg, slot, s->svt);
1008 if (s->left->op == MB_TERM_ADDR_L && s->left->data.i == vnum) {
1010 *tdup = ctree_create_dup (mp, s);
1016 *tdup = ctree_create_dup (mp, s);
1021 g_assert (s->svt != VAL_UNKNOWN);
1024 vnum = mono_allocate_intvar (cfg, slot, s->svt);
1027 mono_get_val_sizes (s->svt, &size, &align);
1028 vnum = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, s->svt);
1031 t = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
1034 t = mono_ctree_new (mp, map_store_svt_type (s->svt), t, s);
1040 mono_store_tree (cfg, -1, t, tdup);
1046 mono_cfg_new (MonoMethod *method, MonoMemPool *mp)
1051 g_assert (((MonoMethodNormal *)method)->header);
1053 cfg = mono_mempool_alloc0 (mp, sizeof (MonoFlowGraph));
1055 cfg->domain = mono_domain_get ();
1056 cfg->method = method;
1059 /* fixme: we should also consider loader optimisation attributes */
1060 cfg->share_code = mono_jit_share_code;
1062 cfg->varinfo = g_array_new (FALSE, TRUE, sizeof (MonoVarInfo));
1064 SET_VARINFO (vi, 0, 0, 0, 0);
1065 g_array_append_val (cfg->varinfo, vi); /* add invalid value at position 0 */
1067 cfg->intvars = mono_mempool_alloc0 (mp, sizeof (guint16) * VAL_DOUBLE *
1068 ((MonoMethodNormal *)method)->header->max_stack);
1073 mono_cfg_free (MonoFlowGraph *cfg)
1077 for (i = 0; i < cfg->block_count; i++) {
1078 if (!cfg->bblocks [i].reached)
1080 g_ptr_array_free (cfg->bblocks [i].forest, TRUE);
1081 g_list_free (cfg->bblocks [i].succ);
1085 g_free (cfg->bcinfo);
1088 g_free (cfg->bblocks);
1090 g_array_free (cfg->varinfo, TRUE);
1094 mono_find_final_block (MonoFlowGraph *cfg, guint32 ip, int type)
1096 MonoMethod *method = cfg->method;
1097 MonoBytecodeInfo *bcinfo = cfg->bcinfo;
1098 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
1099 MonoExceptionClause *clause;
1102 for (i = 0; i < header->num_clauses; ++i) {
1103 clause = &header->clauses [i];
1104 if (MONO_OFFSET_IN_HANDLER (clause, ip))
1107 if (MONO_OFFSET_IN_CLAUSE (clause, ip)) {
1108 if (clause->flags & type) {
1109 g_assert (bcinfo [clause->handler_offset].is_block_start);
1110 return &cfg->bblocks [bcinfo [clause->handler_offset].block_id];
1119 mono_cfg_add_successor (MonoFlowGraph *cfg, MonoBBlock *bb, gint32 target)
1124 g_assert (cfg->bcinfo [target].is_block_start);
1126 tbb = &cfg->bblocks [cfg->bcinfo [target].block_id];
1129 for (l = bb->succ; l; l = l->next) {
1130 MonoBBlock *t = (MonoBBlock *)l->data;
1135 bb->succ = g_list_prepend (bb->succ, tbb);
1139 #define CREATE_BLOCK(t) {if (!bcinfo [t].is_block_start) {block_count++;bcinfo [t].is_block_start = 1; }}
1142 mono_analyze_flow (MonoFlowGraph *cfg)
1144 MonoMethod *method = cfg->method;
1145 register const unsigned char *ip, *end;
1146 MonoMethodHeader *header;
1147 MonoBytecodeInfo *bcinfo;
1148 MonoExceptionClause *clause;
1149 MonoBBlock *bblocks, *bb;
1150 const MonoOpcode *opcode;
1154 header = ((MonoMethodNormal *)method)->header;
1156 bcinfo = g_malloc0 (header->code_size * sizeof (MonoBytecodeInfo));
1157 bcinfo [0].is_block_start = 1;
1162 end = ip + header->code_size;
1164 mono_jit_stats.cil_code_size += header->code_size;
1166 /* fixme: add block boundaries for exceptions */
1167 for (i = 0; i < header->num_clauses; ++i) {
1168 clause = &header->clauses [i];
1169 CREATE_BLOCK (clause->try_offset);
1170 CREATE_BLOCK (clause->handler_offset);
1174 guint32 cli_addr = ip - header->code;
1176 //printf ("IL%04x OPCODE %s\n", cli_addr, mono_opcode_names [*ip]);
1179 CREATE_BLOCK (cli_addr);
1190 opcode = &mono_opcodes [i];
1192 switch (opcode->flow_type) {
1193 case MONO_FLOW_RETURN:
1194 case MONO_FLOW_ERROR:
1197 case MONO_FLOW_BRANCH: /* we handle branch when checking the argument type */
1198 case MONO_FLOW_COND_BRANCH:
1199 case MONO_FLOW_CALL:
1200 case MONO_FLOW_NEXT:
1201 case MONO_FLOW_META:
1204 g_assert_not_reached ();
1207 switch (opcode->argument) {
1208 case MonoInlineNone:
1211 case MonoInlineString:
1212 mono_ldstr (mono_domain_get (), method->klass->image, mono_metadata_token_index (read32 (ip + 1)));
1214 case MonoInlineType:
1215 case MonoInlineField:
1216 case MonoInlineMethod:
1219 case MonoShortInlineR:
1226 case MonoShortInlineVar:
1227 case MonoShortInlineI:
1230 case MonoShortInlineBrTarget:
1232 i = (signed char)*ip;
1234 CREATE_BLOCK (cli_addr + 2 + i);
1238 case MonoInlineBrTarget:
1242 CREATE_BLOCK (cli_addr + 5 + i);
1245 case MonoInlineSwitch: {
1246 gint32 st, target, n;
1250 st = cli_addr + 5 + 4 * n;
1253 for (i = 0; i < n; i++) {
1254 target = read32 (ip) + st;
1256 CREATE_BLOCK (target);
1259 * Note: the code didn't set block_end in switch.
1268 g_assert_not_reached ();
1273 g_assert (block_count);
1275 bb = bblocks = g_malloc0 (sizeof (MonoBBlock) * block_count);
1278 bblocks [0].reached = 1;
1280 for (i = 0; i < header->code_size; i++) {
1281 if (bcinfo [i].is_block_start) {
1283 bb->num = block_count;
1284 bb->forest = g_ptr_array_new ();
1286 bb [-1].length = i - bb [-1].cli_addr;
1287 bcinfo [i].block_id = block_count;
1292 bb [-1].length = header->code_size - bb [-1].cli_addr;
1294 cfg->bcinfo = bcinfo;
1295 cfg->bblocks = bblocks;
1296 cfg->block_count = block_count;
1299 end = ip + header->code_size;
1303 guint32 cli_addr = ip - header->code;
1305 if (bcinfo [cli_addr].is_block_start) {
1306 MonoBBlock *tbb = &cfg->bblocks [bcinfo [cli_addr].block_id];
1307 if (bb && !bb->succ)
1308 bb->succ = g_list_prepend (bb->succ, tbb);
1320 opcode = &mono_opcodes [i];
1322 switch (opcode->argument) {
1323 case MonoInlineNone:
1326 case MonoInlineString:
1327 case MonoInlineType:
1328 case MonoInlineField:
1329 case MonoInlineMethod:
1332 case MonoShortInlineR:
1339 case MonoShortInlineVar:
1340 case MonoShortInlineI:
1343 case MonoShortInlineBrTarget:
1345 i = (signed char)*ip;
1347 mono_cfg_add_successor (cfg, bb, cli_addr + 2 + i);
1348 if (opcode->flow_type == MONO_FLOW_COND_BRANCH)
1349 mono_cfg_add_successor (cfg, bb, cli_addr + 2);
1351 case MonoInlineBrTarget:
1355 mono_cfg_add_successor (cfg, bb, cli_addr + 5 + i);
1356 if (opcode->flow_type == MONO_FLOW_COND_BRANCH)
1357 mono_cfg_add_successor (cfg, bb, cli_addr + 5);
1359 case MonoInlineSwitch: {
1360 gint32 st, target, n;
1364 st = cli_addr + 5 + 4 * n;
1365 mono_cfg_add_successor (cfg, bb, st);
1367 for (i = 0; i < n; i++) {
1368 target = read32 (ip) + st;
1370 mono_cfg_add_successor (cfg, bb, target);
1379 g_assert_not_reached ();
1385 * ves_array_element_address:
1386 * @this: a pointer to the array object
1388 * Returns: the address of an array element.
1391 ves_array_element_address (MonoArray *this, ...)
1398 g_assert (this != NULL);
1402 class = this->obj.vtable->klass;
1404 ind = va_arg(ap, int);
1405 if (this->bounds != NULL) {
1406 ind -= this->bounds [0].lower_bound;
1407 for (i = 1; i < class->rank; i++) {
1408 ind = ind*this->bounds [i].length + va_arg(ap, int) -
1409 this->bounds [i].lower_bound;;
1413 esize = mono_array_element_size (class);
1414 ea = (gpointer*)((char*)this->vector + (ind * esize));
1415 //printf ("AADDRESS %p %p %d\n", this, ea, ind);
1423 mono_array_new_va (MonoMethod *cm, ...)
1425 MonoDomain *domain = mono_domain_get ();
1428 guint32 *lower_bounds;
1429 int pcount = cm->signature->param_count;
1430 int rank = cm->klass->rank;
1435 lengths = alloca (sizeof (guint32) * pcount);
1436 for (i = 0; i < pcount; ++i)
1437 lengths [i] = d = va_arg(ap, int);
1439 if (rank == pcount) {
1440 /* Only lengths provided. */
1441 lower_bounds = NULL;
1443 g_assert (pcount == (rank * 2));
1444 /* lower bounds are first. */
1445 lower_bounds = lengths;
1450 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
1453 #define ADD_TREE(t,a) do { t->cli_addr = a; g_ptr_array_add (forest, (t)); } while (0)
1454 #define PUSH_TREE(t,k) do { int tt = k; *sp = t; t->svt = tt; sp++; } while (0)
1456 #define LOCAL_POS(n) (1 + n)
1459 #define LOCAL_TYPE(n) ((header)->locals [(n)]->type == MONO_TYPE_BOOLEAN && !(header)->locals [(n)]->byref ? &mono_defaults.int32_class->byval_arg : (header)->locals [(n)])
1461 #define LOCAL_TYPE(n) ((header)->locals [(n)])
1464 #define ARG_POS(n) (firstarg + n)
1465 #define ARG_TYPE(n) ((n) ? (signature)->params [(n) - (signature)->hasthis] : \
1466 (signature)->hasthis ? &method->klass->this_arg: (signature)->params [(0)])
1470 * replaces all occurences of variable @varnum in @tree with @copy.
1473 mono_copy_used_var (MonoFlowGraph *cfg, MBTree *tree, int varnum, MBTree **copy)
1479 mono_copy_used_var (cfg, tree->left, varnum, copy);
1481 mono_copy_used_var (cfg, tree->right, varnum, copy);
1484 case MB_TERM_LDIND_I1:
1485 case MB_TERM_LDIND_I2:
1486 case MB_TERM_LDIND_I4:
1487 case MB_TERM_LDIND_I8:
1488 case MB_TERM_LDIND_R4:
1489 case MB_TERM_LDIND_R8:
1490 if (tree->left->op == MB_TERM_ADDR_L &&
1491 tree->left->data.i == varnum) {
1493 tree->left->data.i = (*copy)->left->data.i;
1497 mono_get_val_sizes (tree->svt, &size, &align);
1498 v = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, tree->svt);
1500 t1 = mono_ctree_new_leaf (cfg->mp, MB_TERM_ADDR_L);
1503 t2 = mono_ctree_new_leaf (cfg->mp, MB_TERM_ADDR_L);
1504 t2->data.i = varnum;
1505 t2 = mono_ctree_new (cfg->mp, tree->op, t2, NULL);
1507 t2 = mono_ctree_new (cfg->mp, map_store_svt_type (tree->svt), t1, t2);
1508 t2->svt = tree->svt;
1510 tree->left->data.i = v;
1518 * if a variable is modified and there are still referencence
1519 * to it on the runtime stack we need to store the value into
1520 * a temporary variable and use that value instead of the
1524 mono_stack_duplicate_used_var (MonoFlowGraph *cfg, MBTree **stack, MBTree **sp, int varnum)
1528 while (stack < sp) {
1529 mono_copy_used_var (cfg, *stack, varnum, &res);
1537 check_inlining (MonoMethod *method)
1539 MonoMethodHeader *header;
1540 MonoMethodSignature *signature = method->signature;
1541 register const unsigned char *ip, *end;
1543 int i, arg_used [256];
1547 if (method->inline_info)
1548 return method->inline_count;
1550 method->inline_info = 1;
1552 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
1553 (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
1554 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
1555 (method->klass->marshalbyref) ||
1556 ISSTRUCT (signature->ret))
1559 if (!(header = ((MonoMethodNormal *)method)->header) ||
1560 header->num_clauses)
1563 if (header->num_clauses)
1567 end = ip + header->code_size;
1569 for (i = 0; i < 256; i++)
1573 while (!stop && ip < end) {
1623 case CEE_CONV_OVF_I1_UN:
1624 case CEE_CONV_OVF_I2_UN:
1625 case CEE_CONV_OVF_I4_UN:
1626 case CEE_CONV_OVF_I8_UN:
1627 case CEE_CONV_OVF_U1_UN:
1628 case CEE_CONV_OVF_U2_UN:
1629 case CEE_CONV_OVF_U4_UN:
1630 case CEE_CONV_OVF_U8_UN:
1631 case CEE_CONV_OVF_I_UN:
1632 case CEE_CONV_OVF_U_UN:
1644 case CEE_LDELEM_REF:
1652 case CEE_STELEM_REF:
1653 case CEE_CONV_OVF_I1:
1654 case CEE_CONV_OVF_U1:
1655 case CEE_CONV_OVF_I2:
1656 case CEE_CONV_OVF_U2:
1657 case CEE_CONV_OVF_I4:
1658 case CEE_CONV_OVF_U4:
1659 case CEE_CONV_OVF_I8:
1660 case CEE_CONV_OVF_U8:
1665 case CEE_CONV_OVF_I:
1666 case CEE_CONV_OVF_U:
1668 case CEE_ADD_OVF_UN:
1670 case CEE_MUL_OVF_UN:
1672 case CEE_SUB_OVF_UN:
1718 case CEE_CALLVIRT: {
1722 token = read32 (ip);
1725 cm = mono_get_method (method->klass->image, token, NULL);
1737 int an = (*ip) - CEE_LDARG_0;
1740 arg_used [an] = TRUE;
1748 arg_used [*ip] = TRUE;
1760 if (an > 255 || arg_used [an])
1762 arg_used [an] = TRUE;
1793 !(ip [0] == CEE_RET ||
1795 ip [0] == CEE_STLOC_0 &&
1796 ip [1] == CEE_BR_S &&
1798 ip [3] == CEE_LDLOC_0 &&
1799 ip [4] == CEE_RET)))
1802 if (signature->hasthis && arg_used [0])
1803 method->uses_this = 1;
1805 mono_jit_stats.inlineable_methods++;
1807 return method->inline_count = ip - header->code;
1810 return method->inline_count = -1;
1814 create_outstack (MonoFlowGraph *cfg, MonoBBlock *bb, MBTree **stack, int depth)
1816 MonoMemPool *mp = cfg->mp;
1817 MBTree **c = stack, *t1, *t2;
1818 GPtrArray *forest = bb->forest;
1821 g_assert (bb->reached);
1827 g_assert (bb->outdepth == depth);
1831 bb->outdepth = depth;
1832 bb->outstack = mono_mempool_alloc (mp, depth * sizeof (MBTree *));
1834 for (i = 0; i < depth; i++) {
1835 if ((t1 = mono_store_tree (cfg, i, c [i], &t2)))
1837 bb->outstack [i] = t2;
1842 mark_reached (MonoFlowGraph *cfg, MonoBBlock *target, MBTree **stack, int depth)
1844 MonoMemPool *mp = cfg->mp;
1847 if (target->reached)
1850 target->reached = 1;
1857 if (target->instack) {
1858 g_assert (target->indepth == depth);
1862 target->indepth = depth;
1863 target->instack = mono_mempool_alloc (mp, depth * sizeof (MBTree *));
1865 for (i = 0; i < depth; i++) {
1866 target->instack [i] = ctree_create_dup (mp, stack [i]);
1872 #define MARK_REACHED(bb) do { if (!bb->reached) { bb->reached = 1; }} while (0)
1875 * mono_analyze_stack:
1876 * @cfg: control flow graph
1878 * This is the architecture independent part of JIT compilation.
1879 * It creates a forest of trees which can then be fed into the
1880 * architecture dependent code generation.
1882 * The algorithm is from Andi Krall, the same is used in CACAO
1885 mono_analyze_stack (MonoFlowGraph *cfg)
1887 MonoMethod *method = cfg->method;
1888 MonoMemPool *mp = cfg->mp;
1889 MonoBytecodeInfo *bcinfo = cfg->bcinfo;
1890 MonoMethodHeader *header;
1891 MonoMethodSignature *signature;
1894 MBTree **sp, **stack, **arg_sp, **arg_map = NULL, *t1, *t2, *t3;
1895 register const unsigned char *ip, *end;
1897 int i, j, depth, repeat_count;
1898 int varnum = 0, firstarg = 0, retvtarg = 0;
1899 gboolean repeat, superblock_end;
1900 MonoBBlock *bb, *tbb;
1902 GList *inline_list = NULL;
1904 header = ((MonoMethodNormal *)method)->header;
1905 signature = method->signature;
1906 image = method->klass->image;
1908 /* we add 10 extra slots for method inlining */
1909 maxstack = header->max_stack + 10;
1910 sp = stack = alloca (sizeof (MBTree *) * (maxstack + 1));
1912 if (header->num_locals) {
1915 for (i = 0; i < header->num_locals; ++i) {
1917 size = mono_type_size (LOCAL_TYPE (i), &align);
1918 map_ldind_type (header->locals [i], &svt);
1919 varnum = arch_allocate_var (cfg, size, align, MONO_LOCALVAR, svt);
1921 cfg->locals_start_index = varnum;
1925 if (ISSTRUCT (signature->ret)) {
1930 size = mono_type_size (signature->ret, &align);
1932 retvtarg = varnum = arch_allocate_var (cfg, size, align, MONO_LOCALVAR, VAL_UNKNOWN);
1934 //printf ("VALUETYPE METHOD %s.%s::%s %d\n", method->klass->name_space,
1935 //method->klass->name, method->name, size);
1938 cfg->args_start_index = firstarg = varnum + 1;
1940 if (signature->hasthis) {
1942 thisvar = arch_allocate_var (cfg, sizeof (gpointer), sizeof (gpointer), MONO_ARGVAR, VAL_POINTER);
1943 VARINFO (cfg, thisvar).isvolatile = 1;
1946 if (signature->param_count) {
1949 for (i = 0; i < signature->param_count; ++i) {
1951 size = mono_type_stack_size (signature->params [i], &align);
1952 argvar = arch_allocate_var (cfg, size, align, MONO_ARGVAR, VAL_UNKNOWN);
1953 VARINFO (cfg, argvar).isvolatile = 1;
1957 for (i = 0; i < header->num_clauses; ++i) {
1958 MonoExceptionClause *clause = &header->clauses [i];
1959 tbb = &cfg->bblocks [bcinfo [clause->handler_offset].block_id];
1960 if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) {
1961 tbb->instack = mono_mempool_alloc (mp, sizeof (MBTree *));
1963 tbb->instack [0] = t1 = mono_ctree_new_leaf (mp, MB_TERM_EXCEPTION);
1964 t1->data.i = mono_allocate_excvar (cfg);
1965 t1->svt = VAL_POINTER;
1967 } else if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
1968 mark_reached (cfg, tbb, NULL, 0);
1970 g_warning ("implement me");
1971 g_assert_not_reached ();
1979 superblock_end = TRUE;
1982 //printf ("START\n");
1983 for (i = 0; i < cfg->block_count; i++) {
1984 bb = &cfg->bblocks [i];
1986 //printf ("BBS %d %05x %05x %d %d %d %s\n", i, bb->cli_addr, bb->cli_addr + bb->length, bb->reached, bb->finished, superblock_end, method->name);
1988 if (!bb->reached && !superblock_end) {
1989 MonoBBlock *sbb = &cfg->bblocks [i - 1];
1991 g_assert (sbb->outdepth == (sp - stack));
1993 mark_reached (cfg, bb, sbb->outstack, sbb->outdepth);
1998 if (!bb->finished) {
2002 for (j = 0; j < bb->indepth; j++) {
2003 sp [j] = bb->instack [j];
2009 ip = header->code + bb->cli_addr;
2010 end = ip + bb->length;
2012 forest = bb->forest;
2014 superblock_end = FALSE;
2017 while (inline_list || ip < end) {
2021 MonoInlineInfo *ii = (MonoInlineInfo *)inline_list->data;
2022 if (ip >= ii->end) {
2023 inline_list = g_list_remove_link (inline_list, inline_list);
2025 image = ii->saved_image;
2027 arg_map = ((MonoInlineInfo *)inline_list->data)->arg_map;
2033 cli_addr = ip - header->code;
2036 //if (inline_list) printf ("INLINE IL%04x OPCODE %s\n", cli_addr, mono_opcode_names [*ip]);
2038 //printf ("%d IL%04x OPCODE %s %d %d %d\n", i, cli_addr, mono_opcode_names [*ip],
2039 //forest->len, superblock_end, sp - stack);
2046 t1 = mono_ctree_new (mp, MB_TERM_THROW, *sp, NULL);
2047 ADD_TREE (t1, cli_addr);
2048 superblock_end = TRUE;
2057 token = read32 (ip);
2060 c = mono_class_get (image, token);
2062 t1 = mono_ctree_new_leaf (mp, MB_TERM_NEWOBJ);
2064 t1->svt = VAL_POINTER;
2066 t1 = mono_store_tree (cfg, -1, t1, &t3);
2068 ADD_TREE (t1, cli_addr);
2070 t1 = ctree_create_dup (mp, t3);
2071 t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2072 t2->data.i = sizeof (MonoObject);
2073 t1 = mono_ctree_new (mp, MB_TERM_ADD, t1, t2);
2075 t1 = ctree_create_store (cfg, &c->byval_arg, t1, *sp, FALSE);
2076 ADD_TREE (t1, cli_addr);
2078 PUSH_TREE (t3, VAL_POINTER);
2087 token = read32 (ip);
2091 class = mono_class_get (image, token);
2092 t1 = mono_ctree_new (mp, MB_TERM_UNBOX, *sp, NULL);
2093 t1->data.klass = class;
2095 PUSH_TREE (t1, VAL_POINTER);
2102 t1 = mono_ctree_new (mp, MB_TERM_LDLEN, *sp, NULL);
2103 PUSH_TREE (t1, VAL_I32);
2112 token = read32 (ip);
2116 c = mono_class_get (image, token);
2117 g_assert (c->valuetype);
2119 t1 = ctree_create_load (cfg, &c->byval_arg, *sp, &svt, FALSE);
2120 PUSH_TREE (t1, svt);
2129 token = read32 (ip);
2133 c = mono_class_get (image, token);
2134 g_assert (c->valuetype);
2136 size = mono_class_value_size (c, NULL);
2138 t1 = mono_ctree_new (mp, MB_TERM_STIND_OBJ, sp [0], sp [1]);
2140 ADD_TREE (t1, cli_addr);
2148 ind = mono_metadata_token_index (read32 (ip));
2151 if (cfg->share_code) {
2152 t1 = mono_ctree_new_leaf (mp, MB_TERM_LDSTR);
2155 o = (MonoObject *) mono_ldstr (cfg->domain, image, ind);
2156 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2160 PUSH_TREE (t1, VAL_POINTER);
2166 MonoClassField *field;
2168 int load_addr = *ip == CEE_LDSFLDA;
2171 token = read32 (ip);
2174 /* need to handle fieldrefs */
2175 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
2176 field = mono_field_from_memberref (image, token, &klass);
2177 mono_class_init (klass);
2179 klass = mono_class_get (image,
2180 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
2181 mono_class_init (klass);
2182 field = mono_class_get_field (klass, token);
2187 if (cfg->share_code) {
2188 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2189 t1->data.i = field->offset;
2190 t1 = mono_ctree_new (mp, MB_TERM_LDSFLDA, t1, NULL);
2191 t1->data.klass = klass;
2193 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
2194 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
2195 t1->data.p = (char*)(vt->data) + field->offset;
2201 t1 = ctree_create_load (cfg, field->type, t1, &svt, FALSE);
2204 PUSH_TREE (t1, svt);
2210 MonoClassField *field;
2212 int load_addr = *ip == CEE_LDFLDA;
2215 token = read32 (ip);
2219 /* need to handle fieldrefs */
2220 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
2221 field = mono_field_from_memberref (image, token, &klass);
2222 mono_class_init (klass);
2224 klass = mono_class_get (image,
2225 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
2226 mono_class_init (klass);
2227 field = mono_class_get_field (klass, token);
2231 if (klass->marshalbyref) {
2232 t1 = mono_ctree_new (mp, MB_TERM_REMOTE_LDFLDA, sp [0], NULL);
2233 t1->data.fi.klass = klass;
2234 t1->data.fi.field = field;
2236 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2238 if (klass->valuetype)
2239 t1->data.i = field->offset - sizeof (MonoObject);
2241 t1->data.i = field->offset;
2243 t1 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], t1);
2247 t1 = ctree_create_load (cfg, field->type, t1, &svt, FALSE);
2251 PUSH_TREE (t1, svt);
2256 MonoClassField *field;
2260 token = read32 (ip);
2264 /* need to handle fieldrefs */
2265 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
2266 field = mono_field_from_memberref (image, token, &klass);
2267 mono_class_init (klass);
2269 klass = mono_class_get (image,
2270 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
2271 mono_class_init (klass);
2272 field = mono_class_get_field (klass, token);
2277 if (cfg->share_code) {
2278 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2279 t1->data.i = field->offset;
2280 t1 = mono_ctree_new (mp, MB_TERM_LDSFLDA, t1, NULL);
2281 t1->data.klass = klass;
2283 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
2284 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
2285 t1->data.p = (char*)(vt->data) + field->offset;
2287 t1 = ctree_create_store (cfg, field->type, t1, *sp, FALSE);
2289 ADD_TREE (t1, cli_addr);
2294 MonoClassField *field;
2298 token = read32 (ip);
2302 /* need to handle fieldrefs */
2303 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
2304 field = mono_field_from_memberref (image, token, &klass);
2305 mono_class_init (klass);
2307 klass = mono_class_get (image,
2308 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
2309 mono_class_init (klass);
2310 field = mono_class_get_field (klass, token);
2314 if (klass->marshalbyref) {
2315 t1 = mono_ctree_new (mp, map_remote_stind_type (field->type), sp [0], sp [1]);
2316 t1->data.fi.klass = klass;
2317 t1->data.fi.field = field;
2319 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2320 t1->data.i = klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset;
2321 t1 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], t1);
2322 t1 = ctree_create_store (cfg, field->type, t1, sp [1], FALSE);
2326 ADD_TREE (t1, cli_addr);
2331 guint32 esize, token;
2334 token = read32 (ip);
2338 class = mono_class_get (image, token);
2340 mono_class_init (class);
2342 esize = mono_class_instance_size (class);
2343 if (class->valuetype)
2344 esize -= sizeof (MonoObject);
2346 t1 = mono_ctree_new (mp, MB_TERM_LDELEMA, sp [0], sp [1]);
2348 PUSH_TREE (t1, VAL_POINTER);
2357 t1 = mono_ctree_new_leaf (mp, MB_TERM_BREAK);
2358 ADD_TREE (t1, cli_addr);
2371 t1 = mono_ctree_new (mp, MB_TERM_SWITCH, *sp, NULL);
2372 jt = t1->data.p = mono_alloc_static (sizeof (gpointer) * (n + 2));
2373 st = cli_addr + 5 + 4 * n;
2375 // hack: we store n at position 0
2376 jt [0] = (MonoBBlock *)n;
2378 create_outstack (cfg, bb, stack, sp - stack);
2380 for (k = 1; k <= (n + 1); k++) {
2384 target = read32 (ip) + st;
2387 g_assert (target >= 0 && target <= header->code_size);
2388 g_assert (bcinfo [target].is_block_start);
2389 tbb = &cfg->bblocks [bcinfo [target].block_id];
2390 mark_reached (cfg, tbb, stack, sp - stack);
2394 ADD_TREE (t1, cli_addr);
2399 MonoClass *handle_class;
2402 handle = mono_ldtoken (image, read32 (ip), &handle_class);
2405 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2406 t1->data.p = handle;
2407 PUSH_TREE (t1, VAL_POINTER);
2417 token = read32 (ip);
2418 class = mono_class_get (image, token);
2421 if (cfg->share_code) {
2422 t1 = mono_ctree_new (mp, MB_TERM_NEWARR, *sp, NULL);
2426 MonoClass *ac = mono_array_class_get (&class->byval_arg, 1);
2427 MonoVTable *vt = mono_class_vtable (cfg->domain, ac);
2429 t1 = mono_ctree_new (mp, MB_TERM_NEWARR_SPEC, *sp, NULL);
2433 PUSH_TREE (t1, VAL_POINTER);
2441 token = read32 (ip);
2442 class = mono_class_get (image, token);
2446 t1 = mono_ctree_new (mp, MB_TERM_CPOBJ, sp [0], sp [1]);
2447 ADD_TREE (t1, cli_addr);
2452 MonoMethodSignature *csig;
2454 MBTree *this = NULL;
2456 int k, align, size, args_size = 0;
2461 token = read32 (ip);
2464 cm = mono_get_method (image, token, NULL);
2466 g_assert (!strcmp (cm->name, ".ctor"));
2468 csig = cm->signature;
2469 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
2470 g_assert (csig->hasthis);
2472 arg_sp = sp -= csig->param_count;
2474 if (!cm->klass->inited)
2475 mono_class_init (cm->klass);
2477 if (cm->klass->parent == mono_defaults.array_class) {
2479 this = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2481 } else if (cm->klass == mono_defaults.string_class) {
2483 this = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2486 if (cm->klass->valuetype) {
2487 this = mono_ctree_new_leaf (mp, MB_TERM_NEWSTRUCT);
2488 this->data.i = mono_class_value_size (cm->klass, NULL);
2489 } else if (cfg->share_code) {
2490 this = mono_ctree_new_leaf (mp, MB_TERM_NEWOBJ);
2491 this->data.klass = cm->klass;
2493 MonoVTable *vt = mono_class_vtable (cfg->domain, cm->klass);
2494 this = mono_ctree_new_leaf (mp, MB_TERM_NEWOBJ_SPEC);
2498 this->svt = VAL_POINTER;
2500 t1 = mono_store_tree (cfg, -1, this, &this);
2502 ADD_TREE (t1, cli_addr);
2505 args_size += sizeof (gpointer); /* this argument */
2507 for (k = csig->param_count - 1; k >= 0; k--) {
2508 MonoType *type = cm->signature->params [k];
2510 size = mono_type_stack_size (type, &align);
2511 t1 = mono_ctree_new (mp, map_arg_type (type), arg_sp [k], NULL);
2513 ADD_TREE (t1, cli_addr);
2518 if (newarr || newstr) {
2520 t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2522 t2->data.p = mono_array_new_va;
2524 t2->data.p = arch_create_jit_trampoline (cm);
2527 t1 = mono_ctree_new (mp, MB_TERM_CALL_I4, this, t2);
2529 t1->data.ci.args_size = args_size;
2530 t1->data.ci.vtype_num = 0;
2532 t1->svt = VAL_POINTER;
2534 t1 = mono_store_tree (cfg, -1, t1, &t2);
2536 ADD_TREE (t1, cli_addr);
2537 PUSH_TREE (t2, t2->svt);
2541 t2 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
2542 t2->data.p = arch_create_jit_trampoline (cm);
2544 t1 = mono_ctree_new (mp, map_call_type (csig->ret, &svt), this, t2);
2546 t1->data.ci.args_size = args_size;
2547 t1->data.ci.vtype_num = 0;
2550 ADD_TREE (t1, cli_addr);
2552 t1 = ctree_create_dup (mp, this);
2554 if (cm->klass->valuetype) {
2555 t2 = ctree_create_load (cfg, &cm->klass->byval_arg, t1, &svt, FALSE);
2556 PUSH_TREE (t2, svt);
2558 PUSH_TREE (t1, t1->svt);
2564 case CEE_CALLVIRT: {
2565 MonoMethodSignature *csig;
2567 MBTree *this = NULL;
2569 int k, align, size, args_size = 0;
2570 int virtual = *ip == CEE_CALLVIRT;
2571 gboolean array_set = FALSE;
2572 gboolean array_get = FALSE;
2573 /* fixme: compute this value */
2574 gboolean shared_to_unshared_call = FALSE;
2575 int nargs, vtype_num = 0;
2578 token = read32 (ip);
2581 cm = mono_get_method (image, token, NULL);
2584 if (cm->klass == mono_defaults.string_class &&
2585 *cm->name == '.' && !strcmp (cm->name, ".ctor"))
2586 g_assert_not_reached ();
2588 arg_sp = sp -= cm->signature->param_count;
2590 if ((cm->flags & METHOD_ATTRIBUTE_FINAL && cm->klass != mono_defaults.object_class) ||
2591 !(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
2594 if (mono_jit_inline_code && !virtual && cm->inline_count != -1 &&
2595 (cm->inline_info || check_inlining (cm) >= 0)) {
2596 MonoInlineInfo *ii = alloca (sizeof (MonoInlineInfo));
2599 mono_jit_stats.inlined_methods++;
2601 if (cm->signature->hasthis)
2604 args = cm->signature->param_count + cm->signature->hasthis;
2608 ii->saved_image = image;
2609 ii->arg_map = alloca (args * sizeof (MBTree *));
2610 memcpy (ii->arg_map, sp, args * sizeof (MBTree *));
2612 if (cm->signature->hasthis && !cm->uses_this &&
2613 (ii->arg_map [0]->op != MB_TERM_CHECKTHIS)) {
2614 ii->arg_map [0] = mono_ctree_new (mp, MB_TERM_CHECKTHIS,
2615 ii->arg_map [0], NULL);
2616 ADD_TREE (ii->arg_map [0], cli_addr);
2619 if (cm->inline_count) {
2620 inline_list = g_list_prepend (inline_list, ii);
2621 ip = ((MonoMethodNormal *)cm)->header->code;
2622 ii->end = ip + cm->inline_count;
2623 arg_map = ii->arg_map;
2624 image = cm->klass->image;
2629 csig = cm->signature;
2630 nargs = csig->param_count;
2631 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
2632 g_assert (!virtual || csig->hasthis);
2634 /* fixme: we need to unbox the this pointer for value types ?*/
2635 g_assert (!virtual || !cm->klass->valuetype);
2637 if (cm->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
2638 if (cm->klass->parent == mono_defaults.array_class) {
2639 if (!strcmp (cm->name, "Set")) {
2642 } else if (!strcmp (cm->name, "Get"))
2647 for (k = nargs - 1; k >= 0; k--) {
2648 MonoType *type = cm->signature->params [k];
2649 t1 = mono_ctree_new (mp, map_arg_type (type), arg_sp [k], NULL);
2650 size = mono_type_stack_size (type, &align);
2652 ADD_TREE (t1, cli_addr);
2654 // fixme: align value type arguments to 8 byte boundary on the stack
2657 if (csig->hasthis) {
2659 args_size += sizeof (gpointer);
2661 this = mono_ctree_new_leaf (mp, MB_TERM_NOP);
2663 if (ISSTRUCT (csig->ret)) {
2664 size = mono_type_size (csig->ret, &align);
2665 vtype_num = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, VAL_UNKNOWN);
2671 t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2672 t2->data.p = ves_array_element_address;
2674 t1 = mono_ctree_new (mp, MB_TERM_CALL_I4, this, t2);
2676 t1->data.ci.args_size = args_size;
2677 t1->data.ci.vtype_num = vtype_num;
2679 t1 = mono_ctree_new (mp, map_ldind_type (csig->ret, &svt), t1, NULL);
2682 mono_get_val_sizes (t1->svt, &size, &align);
2683 vnum = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, svt);
2685 t2 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2687 t1 = mono_ctree_new (mp, map_store_svt_type (svt), t2, t1);
2690 ADD_TREE (t1, cli_addr);
2691 t1 = ctree_create_dup (mp, t1);
2692 PUSH_TREE (t1, t1->svt);
2694 } else if (array_set) {
2696 t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2697 t2->data.p = ves_array_element_address;
2699 t1 = mono_ctree_new (mp, MB_TERM_CALL_I4, this, t2);
2701 t1->data.ci.args_size = args_size;
2702 t1->data.ci.vtype_num = vtype_num;
2704 t1 = ctree_create_store (cfg, csig->params [nargs], t1, arg_sp [nargs], FALSE);
2705 ADD_TREE (t1, cli_addr);
2709 if (virtual || (csig->hasthis &&
2710 !(cm->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
2711 (cm->klass->marshalbyref || shared_to_unshared_call))) {
2713 mono_class_init (cm->klass);
2715 if (cm->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
2716 t2 = mono_ctree_new_leaf (mp, MB_TERM_INTF_ADDR);
2718 t2 = mono_ctree_new_leaf (mp, MB_TERM_VFUNC_ADDR);
2723 t2 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
2724 t2->data.p = arch_create_jit_trampoline (cm);
2727 t1 = mono_ctree_new (mp, map_call_type (csig->ret, &svt), this, t2);
2729 t1->data.ci.args_size = args_size;
2730 t1->data.ci.vtype_num = vtype_num;
2733 if (csig->ret->type != MONO_TYPE_VOID) {
2736 ADD_TREE (t1, cli_addr);
2737 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2738 t1->data.i = vtype_num;
2739 PUSH_TREE (t1, VAL_POINTER);
2741 t1 = mono_store_tree (cfg, -1, t1, &t2);
2743 ADD_TREE (t1, cli_addr);
2744 PUSH_TREE (t2, t2->svt);
2747 ADD_TREE (t1, cli_addr);
2757 token = read32 (ip);
2760 c = mono_class_get (image, token);
2762 mono_class_init (c);
2764 t1 = mono_ctree_new (mp, MB_TERM_ISINST, *sp, NULL);
2767 PUSH_TREE (t1, VAL_POINTER);
2772 case CEE_CASTCLASS: {
2776 token = read32 (ip);
2779 c = mono_class_get (image, token);
2781 mono_class_init (c);
2783 t1 = mono_ctree_new (mp, MB_TERM_CASTCLASS, *sp, NULL);
2786 PUSH_TREE (t1, VAL_POINTER);
2791 case CEE_LDC_I4_S: {
2793 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2794 t1->data.i = *(const gint8 *)ip;
2796 PUSH_TREE (t1, VAL_I32);
2801 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2802 t1->data.i = read32 (ip);
2804 PUSH_TREE (t1, VAL_I32);
2816 case CEE_LDC_I4_8: {
2817 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2818 t1->data.i = (*ip) - CEE_LDC_I4_0;
2820 PUSH_TREE (t1, VAL_I32);
2824 //fixme: don't know if this is portable ?
2826 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2828 PUSH_TREE (t1, VAL_POINTER);
2833 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I8);
2834 t1->data.l = read64 (ip);
2836 PUSH_TREE (t1, VAL_I64);
2840 float *f = mono_alloc_static (sizeof (float));
2842 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_R4);
2846 PUSH_TREE (t1, VAL_DOUBLE);
2850 double *d = mono_alloc_static (sizeof (double));
2852 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_R8);
2856 PUSH_TREE (t1, VAL_DOUBLE);
2863 int n = (*ip) - CEE_LDLOC_0;
2866 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2867 t1->data.i = LOCAL_POS (n);
2868 if (!ISSTRUCT (LOCAL_TYPE (n)))
2869 t1 = ctree_create_load (cfg, LOCAL_TYPE (n), t1, &svt, FALSE);
2871 PUSH_TREE (t1, svt);
2877 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2878 t1->data.i = LOCAL_POS (*ip);
2879 if (!ISSTRUCT (LOCAL_TYPE (*ip)))
2880 t1 = ctree_create_load (cfg, LOCAL_TYPE (*ip), t1, &svt, FALSE);
2883 PUSH_TREE (t1, svt);
2886 case CEE_LDLOCA_S: {
2889 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2890 t1->data.i = LOCAL_POS (*ip);
2891 VARINFO (cfg, t1->data.i).isvolatile = 1;
2893 PUSH_TREE (t1, VAL_POINTER);
2900 int n = (*ip) - CEE_STLOC_0;
2904 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2905 t1->data.i = LOCAL_POS (n);
2907 if ((t2 = mono_stack_duplicate_used_var (cfg, stack, sp, t1->data.i)))
2908 ADD_TREE (t2, cli_addr);
2910 t1 = ctree_create_store (cfg, LOCAL_TYPE (n), t1, *sp, FALSE);
2911 ADD_TREE (t1, cli_addr);
2918 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2919 t1->data.i = LOCAL_POS (*ip);
2920 if ((t2 = mono_stack_duplicate_used_var (cfg, stack, sp, t1->data.i)))
2921 ADD_TREE (t2, cli_addr);
2923 t1 = ctree_create_store (cfg, LOCAL_TYPE (*ip), t1, *sp, FALSE);
2925 ADD_TREE (t1, cli_addr);
2930 MAKE_BI_ALU (ADD_OVF)
2931 MAKE_BI_ALU (ADD_OVF_UN)
2933 MAKE_BI_ALU (SUB_OVF)
2934 MAKE_BI_ALU (SUB_OVF_UN)
2938 MAKE_SPILLED_BI_ALU (SHL)
2939 MAKE_SPILLED_BI_ALU (SHR)
2940 MAKE_SPILLED_BI_ALU (SHR_UN)
2941 MAKE_SPILLED_BI_ALU (MUL)
2942 MAKE_SPILLED_BI_ALU (MUL_OVF)
2943 MAKE_SPILLED_BI_ALU (MUL_OVF_UN)
2944 MAKE_SPILLED_BI_ALU (DIV)
2945 MAKE_SPILLED_BI_ALU (DIV_UN)
2946 MAKE_SPILLED_BI_ALU (REM)
2947 MAKE_SPILLED_BI_ALU (REM_UN)
2949 MAKE_LDIND (LDIND_I1, MB_TERM_LDIND_I1, VAL_I32)
2950 MAKE_LDIND (LDIND_U1, MB_TERM_LDIND_U1, VAL_I32)
2951 MAKE_LDIND (LDIND_I2, MB_TERM_LDIND_I2, VAL_I32)
2952 MAKE_LDIND (LDIND_U2, MB_TERM_LDIND_U2, VAL_I32)
2953 MAKE_LDIND (LDIND_I, MB_TERM_LDIND_I4, VAL_I32)
2954 MAKE_LDIND (LDIND_I4, MB_TERM_LDIND_I4, VAL_I32)
2955 MAKE_LDIND (LDIND_REF, MB_TERM_LDIND_REF, VAL_POINTER)
2956 MAKE_LDIND (LDIND_U4, MB_TERM_LDIND_U4, VAL_I32)
2957 MAKE_LDIND (LDIND_I8, MB_TERM_LDIND_I8, VAL_I64)
2958 MAKE_LDIND (LDIND_R4, MB_TERM_LDIND_R4, VAL_DOUBLE)
2959 MAKE_LDIND (LDIND_R8, MB_TERM_LDIND_R8, VAL_DOUBLE)
2961 MAKE_STIND (STIND_I1, MB_TERM_STIND_I1)
2962 MAKE_STIND (STIND_I2, MB_TERM_STIND_I2)
2963 MAKE_STIND (STIND_I, MB_TERM_STIND_I4)
2964 MAKE_STIND (STIND_I4, MB_TERM_STIND_I4)
2965 MAKE_STIND (STIND_I8, MB_TERM_STIND_I8)
2966 MAKE_STIND (STIND_R4, MB_TERM_STIND_R4)
2967 MAKE_STIND (STIND_R8, MB_TERM_STIND_R8)
2968 MAKE_STIND (STIND_REF, MB_TERM_STIND_REF)
2970 MAKE_LDELEM (LDELEM_I1, MB_TERM_LDIND_I1, VAL_I32, 1)
2971 MAKE_LDELEM (LDELEM_U1, MB_TERM_LDIND_U1, VAL_I32, 1)
2972 MAKE_LDELEM (LDELEM_I2, MB_TERM_LDIND_I2, VAL_I32, 2)
2973 MAKE_LDELEM (LDELEM_U2, MB_TERM_LDIND_U2, VAL_I32, 2)
2974 MAKE_LDELEM (LDELEM_I, MB_TERM_LDIND_I4, VAL_I32, 4)
2975 MAKE_LDELEM (LDELEM_I4, MB_TERM_LDIND_I4, VAL_I32, 4)
2976 MAKE_LDELEM (LDELEM_REF, MB_TERM_LDIND_REF, VAL_POINTER, sizeof (gpointer))
2977 MAKE_LDELEM (LDELEM_U4, MB_TERM_LDIND_U4, VAL_I32, 4)
2978 MAKE_LDELEM (LDELEM_I8, MB_TERM_LDIND_I8, VAL_I64, 8)
2979 MAKE_LDELEM (LDELEM_R4, MB_TERM_LDIND_R4, VAL_DOUBLE, 4)
2980 MAKE_LDELEM (LDELEM_R8, MB_TERM_LDIND_R8, VAL_DOUBLE, 8)
2982 MAKE_STELEM (STELEM_I1, MB_TERM_STIND_I1, 1)
2983 MAKE_STELEM (STELEM_I2, MB_TERM_STIND_I2, 2)
2984 MAKE_STELEM (STELEM_I4, MB_TERM_STIND_I4, 4)
2985 MAKE_STELEM (STELEM_I, MB_TERM_STIND_I4, 4)
2986 MAKE_STELEM (STELEM_REF, MB_TERM_STIND_REF, sizeof (gpointer))
2987 MAKE_STELEM (STELEM_I8, MB_TERM_STIND_I8, 8)
2988 MAKE_STELEM (STELEM_R4, MB_TERM_STIND_R4, 4)
2989 MAKE_STELEM (STELEM_R8, MB_TERM_STIND_R8, 8)
2994 t1 = mono_ctree_new (mp, MB_TERM_NEG, sp [0], NULL);
2995 PUSH_TREE (t1, sp [0]->svt);
3001 t1 = mono_ctree_new (mp, MB_TERM_NOT, sp [0], NULL);
3002 PUSH_TREE (t1, sp [0]->svt);
3008 int br_s = (*ip == CEE_BR_S);
3012 target = cli_addr + 2 + (signed char) *ip;
3014 target = cli_addr + 5 + (gint32) read32(ip);
3016 g_assert (target >= 0 && target <= header->code_size);
3017 g_assert (bcinfo [target].is_block_start);
3018 tbb = &cfg->bblocks [bcinfo [target].block_id];
3019 create_outstack (cfg, bb, stack, sp - stack);
3020 mark_reached (cfg, tbb, bb->outstack, bb->outdepth);
3022 t1 = mono_ctree_new_leaf (mp, MB_TERM_BR);
3024 ADD_TREE (t1, cli_addr);
3031 superblock_end = TRUE;
3038 int leave_s = (*ip == CEE_LEAVE_S);
3042 target = cli_addr + 2 + (signed char) *ip;
3044 target = cli_addr + 5 + (gint32) read32(ip);
3046 g_assert (target >= 0 && target <= header->code_size);
3047 g_assert (bcinfo [target].is_block_start);
3048 tbb = &cfg->bblocks [bcinfo [target].block_id];
3050 /* empty the stack */
3053 mark_reached (cfg, tbb, NULL, 0);
3055 /* fixme: fault handler */
3057 if ((hb = mono_find_final_block (cfg, cli_addr, MONO_EXCEPTION_CLAUSE_FINALLY))) {
3058 mark_reached (cfg, hb, NULL, 0);
3059 t1 = mono_ctree_new_leaf (mp, MB_TERM_HANDLER);
3061 ADD_TREE (t1, cli_addr);
3064 t1 = mono_ctree_new_leaf (mp, MB_TERM_BR);
3066 ADD_TREE (t1, cli_addr);
3073 superblock_end = TRUE;
3090 case CEE_BRTRUE_S: {
3092 int near_jump = *ip == CEE_BRTRUE_S;
3096 t1 = mono_ctree_new (mp, MB_TERM_BRTRUE, sp [0], NULL);
3099 target = cli_addr + 2 + (signed char) *ip;
3101 target = cli_addr + 5 + (gint32) read32 (ip);
3103 g_assert (target >= 0 && target <= header->code_size);
3104 g_assert (bcinfo [target].is_block_start);
3105 tbb = &cfg->bblocks [bcinfo [target].block_id];
3106 create_outstack (cfg, bb, stack, sp - stack);
3107 mark_reached (cfg, tbb, bb->outstack, bb->outdepth);
3110 ip += near_jump ? 1: 4;
3111 ADD_TREE (t1, cli_addr);
3115 case CEE_BRFALSE_S: {
3117 int near_jump = *ip == CEE_BRFALSE_S;
3121 t1 = mono_ctree_new (mp, MB_TERM_BRFALSE, sp [0], NULL);
3124 target = cli_addr + 2 + (signed char) *ip;
3126 target = cli_addr + 5 + (gint32) read32 (ip);
3128 g_assert (target >= 0 && target <= header->code_size);
3129 g_assert (bcinfo [target].is_block_start);
3130 tbb = &cfg->bblocks [bcinfo [target].block_id];
3131 create_outstack (cfg, bb, stack, sp - stack);
3132 mark_reached (cfg, tbb, bb->outstack, bb->outdepth);
3135 ip += near_jump ? 1: 4;
3136 ADD_TREE (t1, cli_addr);
3140 MonoType *ret = signature->ret;
3144 if (ret->type != MONO_TYPE_VOID) {
3146 if (ISSTRUCT (ret)) {
3148 t1 = mono_ctree_new (mp, MB_TERM_RET_OBJ, *sp, NULL);
3149 t1->data.i = mono_class_value_size (ret->data.klass, &align);
3151 t1 = mono_ctree_new (mp, MB_TERM_RET, *sp, NULL);
3154 t1 = mono_ctree_new_leaf (mp, MB_TERM_RET_VOID);
3157 t1->last_instr = (ip == (header->code + header->code_size));
3159 ADD_TREE (t1, cli_addr);
3162 g_warning ("more values on stack at IL_%04x: %d", ip - header->code, sp - stack);
3163 mono_print_ctree (cfg, sp [-1]);
3166 superblock_end = TRUE;
3169 case CEE_ENDFINALLY: {
3172 t1 = mono_ctree_new_leaf (mp, MB_TERM_ENDFINALLY);
3173 ADD_TREE (t1, cli_addr);
3174 t1->last_instr = FALSE;
3176 g_assert (sp == stack);
3177 superblock_end = TRUE;
3184 int n = (*ip) - CEE_LDARG_0;
3191 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3192 t1->data.i = ARG_POS (n);
3193 if (!ISSTRUCT (ARG_TYPE (n)))
3194 t1 = ctree_create_load (cfg, ARG_TYPE (n), t1, &svt, TRUE);
3196 PUSH_TREE (t1, svt);
3205 *sp = arg_map [*ip];
3208 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3209 t1->data.i = ARG_POS (*ip);
3210 if (!ISSTRUCT (ARG_TYPE (*ip)))
3211 t1 = ctree_create_load (cfg, ARG_TYPE (*ip), t1, &svt, TRUE);
3212 PUSH_TREE (t1, svt);
3217 case CEE_LDARGA_S: {
3219 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3220 t1->data.i = ARG_POS (*ip);
3221 PUSH_TREE (t1, VAL_POINTER);
3229 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3230 t1->data.i = ARG_POS (*ip);
3231 t1 = ctree_create_store (cfg, ARG_TYPE (*ip), t1, *sp, TRUE);
3233 ADD_TREE (t1, cli_addr);
3241 /* fixme: maybe we should add more of these optimisations */
3242 if (sp [-1]->op == MB_TERM_CONST_I4) {
3244 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
3245 t1->data.i = sp [-1]->data.i;
3246 PUSH_TREE (t1, VAL_I32);
3251 vnum = mono_allocate_intvar (cfg, sp - stack, sp [0]->svt);
3252 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3255 t2 = mono_ctree_new (mp, map_store_svt_type (sp [0]->svt), t1, sp [0]);
3256 t2->svt = sp [0]->svt;
3257 ADD_TREE (t2, cli_addr);
3259 t1 = ctree_create_dup (mp, t2);
3260 PUSH_TREE (t1, t1->svt);
3261 t1 = ctree_create_dup (mp, t1);
3262 PUSH_TREE (t1, t1->svt);
3270 t1 = mono_ctree_new (mp, MB_TERM_POP, *sp, NULL);
3271 ADD_TREE (t1, cli_addr);
3278 t1 = mono_ctree_new (mp, MB_TERM_CONV_U1, *sp, NULL);
3279 PUSH_TREE (t1, VAL_I32);
3284 t1 = mono_ctree_new (mp, MB_TERM_CONV_I1, *sp, NULL);
3285 PUSH_TREE (t1, VAL_I32);
3290 t1 = mono_ctree_new (mp, MB_TERM_CONV_U2, *sp, NULL);
3291 PUSH_TREE (t1, VAL_I32);
3296 t1 = mono_ctree_new (mp, MB_TERM_CONV_I2, *sp, NULL);
3297 PUSH_TREE (t1, VAL_I32);
3303 t1 = mono_ctree_new (mp, MB_TERM_CONV_I4, *sp, NULL);
3304 PUSH_TREE (t1, VAL_I32);
3310 t1 = mono_ctree_new (mp, MB_TERM_CONV_U4, *sp, NULL);
3311 PUSH_TREE (t1, VAL_I32);
3316 t1 = mono_ctree_new (mp, MB_TERM_CONV_I8, *sp, NULL);
3317 PUSH_TREE (t1, VAL_I64);
3322 t1 = mono_ctree_new (mp, MB_TERM_CONV_U8, *sp, NULL);
3323 PUSH_TREE (t1, VAL_I64);
3328 t1 = mono_ctree_new (mp, MB_TERM_CONV_R8, *sp, NULL);
3329 PUSH_TREE (t1, VAL_DOUBLE);
3334 t1 = mono_ctree_new (mp, MB_TERM_CONV_R4, *sp, NULL);
3335 PUSH_TREE (t1, VAL_DOUBLE);
3340 t1 = mono_ctree_new (mp, MB_TERM_CONV_R_UN, *sp, NULL);
3341 PUSH_TREE (t1, VAL_DOUBLE);
3343 case CEE_CONV_OVF_I:
3344 case CEE_CONV_OVF_I4:
3347 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I4, *sp, NULL);
3348 PUSH_TREE (t1, VAL_I32);
3350 case CEE_CONV_OVF_I_UN:
3351 case CEE_CONV_OVF_I4_UN:
3354 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I4_UN, *sp, NULL);
3355 PUSH_TREE (t1, VAL_I32);
3357 case CEE_CONV_OVF_U:
3358 case CEE_CONV_OVF_U4:
3361 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U4, *sp, NULL);
3362 PUSH_TREE (t1, VAL_I32);
3364 case CEE_CONV_OVF_I1:
3367 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I1, *sp, NULL);
3368 PUSH_TREE (t1, VAL_I32);
3370 case CEE_CONV_OVF_I1_UN:
3373 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I1_UN, *sp, NULL);
3374 PUSH_TREE (t1, VAL_I32);
3376 case CEE_CONV_OVF_U1_UN:
3379 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U1_UN, *sp, NULL);
3380 PUSH_TREE (t1, VAL_I32);
3382 case CEE_CONV_OVF_U1:
3385 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U1, *sp, NULL);
3386 PUSH_TREE (t1, VAL_I32);
3388 case CEE_CONV_OVF_I2:
3391 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I2, *sp, NULL);
3392 PUSH_TREE (t1, VAL_I32);
3394 case CEE_CONV_OVF_U2_UN:
3397 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U2_UN, *sp, NULL);
3398 PUSH_TREE (t1, VAL_I32);
3400 case CEE_CONV_OVF_U2:
3403 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U2, *sp, NULL);
3404 PUSH_TREE (t1, VAL_I32);
3406 case CEE_CONV_OVF_I2_UN:
3409 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I2_UN, *sp, NULL);
3410 PUSH_TREE (t1, VAL_I32);
3412 case CEE_CONV_OVF_U8:
3415 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U8, *sp, NULL);
3416 PUSH_TREE (t1, VAL_I32);
3418 case CEE_CONV_OVF_U_UN:
3419 case CEE_CONV_OVF_U4_UN:
3420 // fixme: raise exceptions ?
3423 t1 = mono_ctree_new (mp, MB_TERM_CONV_I4, *sp, NULL);
3424 PUSH_TREE (t1, VAL_I32);
3426 case CEE_CONV_OVF_I8_UN:
3429 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I8_UN, *sp, NULL);
3430 PUSH_TREE (t1, VAL_I64);
3441 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3442 t1->data.i = LOCAL_POS (n);
3443 if (!ISSTRUCT (LOCAL_TYPE (n)))
3444 t1 = ctree_create_load (cfg, LOCAL_TYPE (n), t1, &svt, FALSE);
3447 PUSH_TREE (t1, svt);
3453 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3454 t1->data.i = LOCAL_POS (read16 (ip));
3455 VARINFO (cfg, t1->data.i).isvolatile = 1;
3457 PUSH_TREE (t1, VAL_POINTER);
3464 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3465 t1->data.i = LOCAL_POS (read16 (ip));
3466 if ((t2 = mono_stack_duplicate_used_var (cfg, stack, sp, t1->data.i)))
3467 ADD_TREE (t2, cli_addr);
3469 t1 = ctree_create_store (cfg, LOCAL_TYPE (read16 (ip)), t1, *sp, FALSE);
3471 ADD_TREE (t1, cli_addr);
3483 t1 = mono_ctree_new_leaf (mp, MB_TERM_RETHROW);
3484 t1->data.i = mono_allocate_excvar (cfg);
3485 ADD_TREE (t1, cli_addr);
3492 token = read32 (ip);
3495 cm = mono_get_method (image, token, NULL);
3498 t1 = mono_ctree_new_leaf (mp, MB_TERM_LDFTN);
3500 PUSH_TREE (t1, VAL_POINTER);
3503 case CEE_LDVIRTFTN: {
3507 token = read32 (ip);
3511 cm = mono_get_method (image, token, NULL);
3514 if (cm->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
3515 t2 = mono_ctree_new_leaf (mp, MB_TERM_INTF_ADDR);
3517 t2 = mono_ctree_new_leaf (mp, MB_TERM_VFUNC_ADDR);
3521 t1 = mono_ctree_new (mp, MB_TERM_LDVIRTFTN, *sp, t2);
3523 PUSH_TREE (t1, VAL_POINTER);
3532 token = read32 (ip);
3533 class = mono_class_get (image, token);
3537 t1 = mono_ctree_new (mp, MB_TERM_INITOBJ, *sp, NULL);
3538 t1->data.i = mono_class_value_size (class, NULL);
3539 ADD_TREE (t1, cli_addr);
3549 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3550 t1->data.i = ARG_POS (n);
3551 if (!ISSTRUCT (ARG_TYPE (n)))
3552 t1 = ctree_create_load (cfg, ARG_TYPE (n), t1, &svt, TRUE);
3553 PUSH_TREE (t1, svt);
3561 token = read32 (ip);
3563 type = mono_type_create_from_typespec (image, token);
3564 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
3565 t1->data.i = mono_type_size (type, &align);
3566 mono_metadata_free_type (type);
3567 PUSH_TREE (t1, VAL_I32);
3570 case CEE_UNALIGNED_: {
3572 // fixme: implement me
3575 case CEE_VOLATILE_: {
3577 // fixme: implement me
3581 g_error ("Unimplemented opcode at IL_%04x "
3582 "0xFE %02x", ip - header->code, *ip);
3587 g_warning ("unknown instruction `%s' at IL_%04X",
3588 mono_opcode_names [*ip], ip - header->code);
3589 if (mono_debug_handle) {
3593 mono_print_forest (cfg, forest);
3594 g_assert_not_reached ();
3598 if ((depth = sp - stack)) {
3599 //printf ("DEPTH %d %d\n", depth, sp [0]->op);
3600 //mono_print_forest (cfg, forest);
3601 create_outstack (cfg, bb, stack, sp - stack);
3605 superblock_end = TRUE;
3608 superblock_end = TRUE;
3609 //printf ("unreached block %d\n", i);
3611 if (repeat_count >= 10) {
3612 /*mono_print_forest (cfg, forest);
3613 g_warning ("repeat count exceeded at ip: 0x%04x in %s\n", bb->cli_addr, cfg->method->name);*/
3617 //printf ("BBE %d %d %d %d\n", i, bb->reached, bb->finished, superblock_end);
3621 //printf ("REPEAT %d\n", repeat);
3622 mono_jit_stats.analyze_stack_repeat++;
3627 //printf ("FINISHED\n");
3630 /* this function is never called */
3632 ves_array_set (MonoArray *this, ...)
3634 g_assert_not_reached ();
3637 /* this function is never called */
3639 ves_array_get (MonoArray *this, ...)
3641 g_assert_not_reached ();
3646 * @assembly: reference to an assembly
3647 * @argc: argument count
3648 * @argv: argument vector
3650 * Start execution of a program.
3653 mono_jit_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
3655 MonoImage *image = assembly->image;
3656 MonoCLIImageInfo *iinfo;
3661 iinfo = image->image_info;
3662 method = mono_get_method (image, iinfo->cli_cli_header.ch_entry_point, NULL);
3664 rval = mono_runtime_run_main (method, argc, argv, &exc);
3667 mono_print_unhandled_exception (exc);
3672 #ifdef PLATFORM_WIN32
3673 #define GET_CONTEXT \
3674 struct sigcontext *ctx = (struct sigcontext*)_dummy;
3676 #define GET_CONTEXT \
3677 void **_p = (void **)&_dummy; \
3678 struct sigcontext *ctx = (struct sigcontext *)++_p;
3682 sigfpe_signal_handler (int _dummy)
3687 exc = mono_get_exception_divide_by_zero ();
3689 arch_handle_exception (ctx, exc);
3691 g_error ("we should never reach this code");
3695 sigill_signal_handler (int _dummy)
3700 exc = mono_get_exception_execution_engine ("SIGILL");
3702 arch_handle_exception (ctx, exc);
3704 g_error ("we should never reach this code");
3708 sigsegv_signal_handler (int _dummy)
3713 exc = mono_get_exception_null_reference ();
3715 arch_handle_exception (ctx, exc);
3717 g_error ("we should never reach this code");
3721 * mono_thread_abort:
3722 * @obj: exception object
3724 * abort the thread, print exception information and stack trace
3727 mono_thread_abort (MonoObject *obj)
3729 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
3730 MonoDomain *domain = mono_domain_get ();
3731 MonoClassField *field;
3737 longjmp (*jit_tls->env, obj);
3740 field=mono_class_get_field_from_name(mono_defaults.appdomain_class, "UnhandledException");
3744 d = *(MonoDelegate **)(((char *)domain->domain) + field->offset);
3747 mono_print_unhandled_exception (obj);
3749 /* FIXME: call the event handler */
3750 g_assert_not_reached ();
3758 mono_thread_start_cb (gpointer stack_start)
3760 MonoJitTlsData *jit_tls;
3762 jit_tls = g_new0 (MonoJitTlsData, 1);
3764 TlsSetValue (mono_jit_tls_id, jit_tls);
3766 jit_tls->abort_func = mono_thread_abort;
3769 static CRITICAL_SECTION ms;
3772 mono_jit_init (char *file) {
3773 #ifndef PLATFORM_WIN32
3774 struct sigaction sa;
3780 #ifdef PLATFORM_WIN32
3782 win32_seh_set_handler(SIGFPE, sigfpe_signal_handler);
3783 win32_seh_set_handler(SIGILL, sigill_signal_handler);
3784 win32_seh_set_handler(SIGSEGV, sigsegv_signal_handler);
3785 #else /* !PLATFORM_WIN32 */
3787 sa.sa_handler = sigfpe_signal_handler;
3788 sigemptyset (&sa.sa_mask);
3790 g_assert (syscall (SYS_sigaction, SIGFPE, &sa, NULL) != -1);
3793 sa.sa_handler = sigill_signal_handler;
3794 sigemptyset (&sa.sa_mask);
3796 g_assert (syscall (SYS_sigaction, SIGILL, &sa, NULL) != -1);
3800 sa.sa_handler = sigsegv_signal_handler;
3801 sigemptyset (&sa.sa_mask);
3803 g_assert (syscall (SYS_sigaction, SIGSEGV, &sa, NULL) != -1);
3805 #endif /* PLATFORM_WIN32 */
3808 mono_add_internal_call ("System.Array::Set", ves_array_set);
3809 mono_add_internal_call ("System.Array::Get", ves_array_get);
3810 mono_add_internal_call ("System.Array::Address", ves_array_element_address);
3812 metadata_section = &ms;
3813 InitializeCriticalSection (metadata_section);
3815 mono_jit_tls_id = TlsAlloc ();
3816 mono_thread_start_cb (&file);
3818 mono_install_trampoline (arch_create_jit_trampoline);
3819 mono_install_remoting_trampoline (arch_create_remoting_trampoline);
3820 mono_install_handler (arch_get_throw_exception ());
3821 mono_install_runtime_invoke (arch_runtime_invoke);
3823 domain = mono_init (file);
3824 mono_runtime_init (domain);
3825 mono_thread_init (domain, mono_thread_start_cb);
3826 mono_network_init ();
3827 mono_delegate_init ();
3833 mono_jit_cleanup (MonoDomain *domain)
3835 if (mono_debug_handle)
3836 mono_debug_close (mono_debug_handle);
3838 #ifdef PLATFORM_WIN32
3839 win32_seh_cleanup();
3842 mono_delegate_cleanup ();
3843 mono_network_cleanup ();
3844 mono_thread_cleanup ();
3846 mono_domain_unload (domain, TRUE);
3848 if (mono_jit_stats.enabled) {
3849 g_print ("Mono Jit statistics\n");
3850 g_print ("Compiled methods: %ld\n", mono_jit_stats.methods_compiled);
3851 g_print ("Methods cache lookup: %ld\n", mono_jit_stats.methods_lookups);
3852 g_print ("Method trampolines: %ld\n", mono_jit_stats.method_trampolines);
3853 g_print ("Allocated vars: %ld\n", mono_jit_stats.allocate_var);
3854 g_print ("Analyze stack repeat: %ld\n", mono_jit_stats.analyze_stack_repeat);
3855 g_print ("Compiled CIL code size: %ld\n", mono_jit_stats.cil_code_size);
3856 g_print ("Native code size: %ld\n", mono_jit_stats.native_code_size);
3857 g_print ("Max code size ratio: %.2f (%s::%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
3858 mono_jit_stats.max_ratio_method->klass->name, mono_jit_stats.max_ratio_method->name);
3859 g_print ("Biggest method: %ld (%s::%s)\n", mono_jit_stats.biggest_method_size,
3860 mono_jit_stats.biggest_method->klass->name, mono_jit_stats.biggest_method->name);
3861 g_print ("Code reallocs: %ld\n", mono_jit_stats.code_reallocs);
3862 g_print ("Allocated code size: %ld\n", mono_jit_stats.allocated_code_size);
3863 g_print ("Inlineable methods: %ld\n", mono_jit_stats.inlineable_methods);
3864 g_print ("Inlined methods: %ld\n", mono_jit_stats.inlined_methods);
3866 g_print ("\nCreated object count: %ld\n", mono_stats.new_object_count);
3867 g_print ("Initialized classes: %ld\n", mono_stats.initialized_class_count);
3868 g_print ("Used classes: %ld\n", mono_stats.used_class_count);
3869 g_print ("Static data size: %ld\n", mono_stats.class_static_data_size);
3870 g_print ("VTable data size: %ld\n", mono_stats.class_vtable_size);
3873 DeleteCriticalSection (metadata_section);