2 * jit.c: The mono JIT compiler.
5 * Dietmar Maurer (dietmar@ximian.com)
7 * (C) 2001 Ximian, Inc.
11 #include <mono/os/gc_wrapper.h>
18 #include <mono/metadata/verify.h>
19 #include <mono/metadata/assembly.h>
20 #include <mono/metadata/loader.h>
21 #include <mono/metadata/tabledefs.h>
22 #include <mono/metadata/class.h>
23 #include <mono/metadata/object.h>
24 #include <mono/metadata/debug-helpers.h>
25 #include <mono/metadata/opcodes.h>
26 #include <mono/metadata/mono-endian.h>
27 #include <mono/metadata/tokentype.h>
28 #include <mono/metadata/threads.h>
29 #include <mono/metadata/socket-io.h>
30 #include <mono/metadata/appdomain.h>
31 #include <mono/arch/x86/x86-codegen.h>
32 #include <mono/io-layer/io-layer.h>
33 #include <mono/metadata/profiler-private.h>
34 #include <mono/metadata/marshal.h>
43 * if OPT_BOOL is defined we use 32bit to store boolean local variables. This
44 * gives great speedup for boolean expressions, but unfortunately it changes
45 * semantics, so i disable it until we have a real solution */
46 /* #define OPT_BOOL */
48 #define MAKE_CJUMP(name) \
50 case CEE_##name##_S: { \
52 int near_jump = *ip == CEE_##name##_S; \
55 t1 = mono_ctree_new (mp, MB_TERM_COMPARE, sp [0], sp [1]); \
56 t1 = mono_ctree_new (mp, MB_TERM_CBRANCH, t1, NULL); \
58 target = cli_addr + 2 + (signed char) *ip; \
60 target = cli_addr + 5 + (gint32) read32 (ip); \
61 g_assert (target >= 0 && target <= header->code_size); \
62 g_assert (bcinfo [target].is_block_start); \
63 tbb = &cfg->bblocks [bcinfo [target].block_id]; \
64 create_outstack (cfg, bb, stack, sp - stack); \
65 mark_reached (cfg, tbb, bb->outstack, bb->outdepth); \
66 t1->data.bi.target = tbb; \
67 t1->data.bi.cond = CEE_##name; \
68 ADD_TREE (t1, cli_addr); \
69 ip += near_jump ? 1: 4; \
73 #define MAKE_BI_ALU(name) \
77 t1 = mono_ctree_new (mp, MB_TERM_##name, sp [0], sp [1]); \
78 PUSH_TREE (t1, sp [0]->svt); \
83 #define MAKE_SPILLED_BI_ALU1(name, s1, s2) { \
84 t1 = mono_ctree_new (mp, MB_TERM_##name, s1, s2); \
85 PUSH_TREE (t1, s1->svt); }
87 #define MAKE_SPILLED_BI_ALU1(name, s1, s2) \
88 t1 = mono_ctree_new (mp, MB_TERM_##name, s1, s2); \
90 t1 = mono_store_tree (cfg, -1, t1, &t2); \
92 ADD_TREE (t1, cli_addr); \
93 PUSH_TREE (t2, t2->svt);
96 #define MAKE_CMP(cname) \
100 t1 = mono_ctree_new (mp, MB_TERM_COMPARE, sp [0], sp [1]); \
101 t1 = mono_ctree_new (mp, MB_TERM_CSET, t1, NULL); \
102 t1->data.i = CEE_##cname; \
103 PUSH_TREE (t1, VAL_I32); \
107 #define MAKE_SPILLED_BI_ALU(name) \
111 MAKE_SPILLED_BI_ALU1 (name, sp [0], sp [1]) \
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 /* generate bound checking */
216 gboolean mono_jit_boundcheck = TRUE;
219 gboolean mono_inline_memcpy = TRUE;
221 /* Use alternative (faster) sequence to convert FP values to integers */
222 gboolean mono_use_fast_iconv = FALSE;
224 /* TLS id to store jit data */
225 guint32 mono_jit_tls_id;
227 /* issue a breakpoint on unhandled excepions */
228 gboolean mono_break_on_exc = FALSE;
230 MonoDebugFormat mono_debug_format = MONO_DEBUG_FORMAT_NONE;
232 /* If non-zero, insert a breakpoint when compiling the next method.
233 * If positive, interpret this variable as a counter and decrement
234 * it after setting the breakpoint. */
235 int mono_debug_insert_breakpoint = 0;
237 MonoJitStats mono_jit_stats;
239 CRITICAL_SECTION *metadata_section = NULL;
242 * We sometimes need static data, for example the forest generator need it to
243 * store constants or class data.
245 inline static gpointer
246 mono_alloc_static (int size)
248 return g_malloc (size);
250 inline static gpointer
251 mono_alloc_static0 (int size)
253 return g_malloc0 (size);
256 typedef void (*MonoCCtor) (void);
259 mono_allocate_intvar (MonoFlowGraph *cfg, int slot, MonoValueType type)
261 int size, align, vnum, pos;
263 g_assert (type != VAL_UNKNOWN);
265 /* take care if you modify MonoValueType */
266 g_assert (VAL_DOUBLE == 4);
268 /* fixme: machine dependant */
269 if (type == VAL_POINTER)
270 type = VAL_I32; /* VAL_I32 and VAL_POINTER share the same slot */
272 pos = type - 1 + slot * VAL_DOUBLE;
274 if ((vnum = cfg->intvars [pos]))
276 mono_get_val_sizes (type, &size, &align);
278 cfg->intvars[pos] = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, type);
280 return cfg->intvars[pos];
284 mono_allocate_excvar (MonoFlowGraph *cfg)
289 cfg->excvar = arch_allocate_var (cfg, 4, 4, MONO_TEMPVAR, VAL_POINTER);
291 VARINFO (cfg, cfg->excvar).isvolatile = 1;
297 * mono_jit_runtime_invoke:
298 * @method: the method to invoke
300 * @params: array of parameter values.
301 * @exc: used to catch exceptions objects
304 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
307 MonoObject *(*runtime_invoke) (MonoObject *this, void **params, MonoObject **exc);
309 invoke = mono_marshal_get_runtime_invoke (method);
310 runtime_invoke = mono_compile_method (invoke);
311 return runtime_invoke (obj, params, exc);
316 * @cfg: pointer to the control flow graph
317 * @type: the type of the value to load
318 * @addr: the address of the value
320 * Creates a tree to load the value at address @addr.
322 inline static MBTree *
323 ctree_create_load (MonoFlowGraph *cfg, MonoType *type, MBTree *addr, MonoValueType *svt, gboolean arg)
325 MonoMemPool *mp = cfg->mp;
330 ldind = mono_map_ldarg_type (type, svt);
332 ldind = mono_map_ldind_type (type, svt);
334 t = mono_ctree_new (mp, ldind, addr, NULL);
340 * ctree_create_store:
341 * @mp: pointer to a memory pool
342 * @s: the value (tree) to store
343 * @type: the type of the value
344 * @addr: the address of the value
346 * Creates a tree to store the value @s at address @addr.
348 inline static MBTree *
349 ctree_create_store (MonoFlowGraph *cfg, MonoType *type, MBTree *addr,
350 MBTree *s, gboolean arg)
352 MonoMemPool *mp = cfg->mp;
357 stind = mono_map_starg_type (type);
359 stind = mono_map_stind_type (type);
361 t = mono_ctree_new (mp, stind, addr, s);
363 if (MONO_TYPE_ISSTRUCT (type))
364 t->data.i = mono_class_value_size (type->data.klass, NULL);
369 inline static MBTree *
370 ctree_dup_address (MonoMemPool *mp, MBTree *s)
378 t = mono_ctree_new_leaf (mp, s->op);
379 t->data.i = s->data.i;
380 t->svt = VAL_POINTER;
383 g_warning ("unknown tree opcode %d", s->op);
384 g_assert_not_reached ();
391 * Create a duplicate of the value of a tree. This is
392 * easy for trees starting with LDIND/STIND, since the
393 * duplicate is simple a LDIND tree with the same address.
394 * For other trees we have to split the tree into one tree
395 * storing the value to a new temporary variable, and
396 * another tree which loads that value back. We can then
397 * duplicate the second tree.
400 ctree_create_dup (MonoMemPool *mp, MBTree *s)
405 case MB_TERM_STIND_I1:
406 case MB_TERM_LDIND_I1:
407 t = ctree_dup_address (mp, s->left);
408 t = mono_ctree_new (mp, MB_TERM_LDIND_I1, t, NULL);
411 case MB_TERM_STIND_I2:
412 case MB_TERM_LDIND_I2:
413 t = ctree_dup_address (mp, s->left);
414 t = mono_ctree_new (mp, MB_TERM_LDIND_I2, t, NULL);
417 case MB_TERM_STIND_I4:
418 case MB_TERM_LDIND_I4:
419 t = ctree_dup_address (mp, s->left);
420 t = mono_ctree_new (mp, MB_TERM_LDIND_I4, t, NULL);
423 case MB_TERM_STIND_I8:
424 case MB_TERM_LDIND_I8:
425 t = ctree_dup_address (mp, s->left);
426 t = mono_ctree_new (mp, MB_TERM_LDIND_I8, t, NULL);
429 case MB_TERM_STIND_R4:
430 case MB_TERM_LDIND_R4:
431 t = ctree_dup_address (mp, s->left);
432 t = mono_ctree_new (mp, MB_TERM_LDIND_R4, t, NULL);
435 case MB_TERM_STIND_R8:
436 case MB_TERM_LDIND_R8:
437 t = ctree_dup_address (mp, s->left);
438 t = mono_ctree_new (mp, MB_TERM_LDIND_R8, t, NULL);
441 case MB_TERM_STIND_OBJ:
442 case MB_TERM_LDIND_OBJ:
443 t = ctree_dup_address (mp, s->left);
444 t = mono_ctree_new (mp, MB_TERM_LDIND_OBJ, t, NULL);
445 t->svt = VAL_UNKNOWN;
448 g_warning ("unknown op \"%s\"", mono_burg_term_string [s->op]);
449 g_assert_not_reached ();
456 mono_store_tree (MonoFlowGraph *cfg, int slot, MBTree *s, MBTree **tdup)
458 MonoMemPool *mp = cfg->mp;
463 case MB_TERM_STIND_I1:
464 case MB_TERM_LDIND_I1:
465 case MB_TERM_STIND_I2:
466 case MB_TERM_LDIND_I2:
467 case MB_TERM_STIND_I4:
468 case MB_TERM_LDIND_I4:
469 case MB_TERM_STIND_I8:
470 case MB_TERM_LDIND_I8:
471 case MB_TERM_STIND_R4:
472 case MB_TERM_LDIND_R4:
473 case MB_TERM_STIND_R8:
474 case MB_TERM_LDIND_R8: {
476 vnum = mono_allocate_intvar (cfg, slot, s->svt);
478 if (s->left->op == MB_TERM_ADDR_L && s->left->data.i == vnum) {
480 *tdup = ctree_create_dup (mp, s);
486 *tdup = ctree_create_dup (mp, s);
491 g_assert (s->svt != VAL_UNKNOWN);
495 vnum = mono_allocate_intvar (cfg, slot, s->svt);
498 mono_get_val_sizes (s->svt, &size, &align);
499 vnum = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, s->svt);
502 t = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
505 t = mono_ctree_new (mp, mono_map_store_svt_type (s->svt), t, s);
511 *tdup = ctree_create_dup (mp, t);
517 mono_find_final_block (MonoFlowGraph *cfg, guint32 ip, guint32 target, int type)
519 MonoMethod *method = cfg->method;
520 MonoBytecodeInfo *bcinfo = cfg->bcinfo;
521 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
522 MonoExceptionClause *clause;
525 for (i = 0; i < header->num_clauses; ++i) {
526 clause = &header->clauses [i];
528 if (MONO_OFFSET_IN_CLAUSE (clause, ip) &&
529 (!MONO_OFFSET_IN_CLAUSE (clause, target))) {
530 if (clause->flags & type) {
531 g_assert (bcinfo [clause->handler_offset].is_block_start);
532 return &cfg->bblocks [bcinfo [clause->handler_offset].block_id];
540 mono_cfg_add_successor (MonoFlowGraph *cfg, MonoBBlock *bb, gint32 target)
545 g_assert (cfg->bcinfo [target].is_block_start);
547 tbb = &cfg->bblocks [cfg->bcinfo [target].block_id];
550 for (l = bb->succ; l; l = l->next) {
551 MonoBBlock *t = (MonoBBlock *)l->data;
556 bb->succ = g_list_prepend (bb->succ, tbb);
560 #define CREATE_BLOCK(t) {if (!bcinfo [t].is_block_start) {block_count++;bcinfo [t].is_block_start = 1; }}
563 mono_analyze_flow (MonoFlowGraph *cfg)
565 MonoMethod *method = cfg->method;
566 const unsigned char *ip, *end;
567 MonoMethodHeader *header;
568 MonoBytecodeInfo *bcinfo;
569 MonoExceptionClause *clause;
570 MonoBBlock *bblocks, *bb;
571 const MonoOpcode *opcode;
575 header = ((MonoMethodNormal *)method)->header;
577 bcinfo = g_malloc0 (header->code_size * sizeof (MonoBytecodeInfo));
578 bcinfo [0].is_block_start = 1;
583 end = ip + header->code_size;
585 mono_jit_stats.cil_code_size += header->code_size;
587 for (i = 0; i < header->num_clauses; ++i) {
588 clause = &header->clauses [i];
590 CREATE_BLOCK (clause->try_offset);
591 CREATE_BLOCK (clause->handler_offset);
593 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER)
594 CREATE_BLOCK (clause->token_or_filter);
598 guint32 cli_addr = ip - header->code;
600 //printf ("IL%04x OPCODE %s\n", cli_addr, mono_opcode_names [*ip]);
603 CREATE_BLOCK (cli_addr);
607 i = mono_opcode_value (&ip);
609 opcode = &mono_opcodes [i];
611 switch (opcode->flow_type) {
612 case MONO_FLOW_RETURN:
613 case MONO_FLOW_ERROR:
616 case MONO_FLOW_BRANCH: /* we handle branch when checking the argument type */
617 case MONO_FLOW_COND_BRANCH:
623 g_assert_not_reached ();
626 switch (opcode->argument) {
630 case MonoInlineString:
631 mono_ldstr (mono_domain_get (), method->klass->image, mono_metadata_token_index (read32 (ip + 1)));
634 case MonoInlineField:
635 case MonoInlineMethod:
638 case MonoShortInlineR:
645 case MonoShortInlineVar:
646 case MonoShortInlineI:
649 case MonoShortInlineBrTarget:
651 i = (signed char)*ip;
653 CREATE_BLOCK (cli_addr + 2 + i);
657 case MonoInlineBrTarget:
661 CREATE_BLOCK (cli_addr + 5 + i);
664 case MonoInlineSwitch: {
665 gint32 st, target, n;
669 st = cli_addr + 5 + 4 * n;
672 for (i = 0; i < n; i++) {
673 target = read32 (ip) + st;
675 CREATE_BLOCK (target);
678 * Note: the code didn't set block_end in switch.
687 g_assert_not_reached ();
692 g_assert (block_count);
694 bb = bblocks = g_malloc0 (sizeof (MonoBBlock) * block_count);
697 bblocks [0].reached = 1;
699 for (i = 0; i < header->code_size; i++) {
700 if (bcinfo [i].is_block_start) {
702 bb->num = block_count;
703 bb->forest = g_ptr_array_new ();
705 bb [-1].length = i - bb [-1].cli_addr;
706 bcinfo [i].block_id = block_count;
711 bb [-1].length = header->code_size - bb [-1].cli_addr;
713 cfg->bcinfo = bcinfo;
714 cfg->bblocks = bblocks;
715 cfg->block_count = block_count;
717 mono_jit_stats.basic_blocks += block_count;
718 mono_jit_stats.max_basic_blocks = MAX (block_count, mono_jit_stats.max_basic_blocks);
720 for (i = 0; i < header->num_clauses; ++i) {
721 MonoBBlock *sbb, *tbb;
722 clause = &header->clauses [i];
723 sbb = &cfg->bblocks [bcinfo [clause->try_offset].block_id];
724 tbb = &cfg->bblocks [bcinfo [clause->handler_offset].block_id];
725 g_assert (sbb && tbb);
726 sbb->succ = g_list_prepend (sbb->succ, tbb);
730 end = ip + header->code_size;
734 guint32 cli_addr = ip - header->code;
736 if (bcinfo [cli_addr].is_block_start) {
737 MonoBBlock *tbb = &cfg->bblocks [bcinfo [cli_addr].block_id];
739 bb->succ = g_list_prepend (bb->succ, tbb);
744 i = mono_opcode_value (&ip);
746 opcode = &mono_opcodes [i];
748 switch (opcode->argument) {
752 case MonoInlineString:
754 case MonoInlineField:
755 case MonoInlineMethod:
758 case MonoShortInlineR:
765 case MonoShortInlineVar:
766 case MonoShortInlineI:
769 case MonoShortInlineBrTarget:
771 i = (signed char)*ip;
773 mono_cfg_add_successor (cfg, bb, cli_addr + 2 + i);
774 if (opcode->flow_type == MONO_FLOW_COND_BRANCH)
775 mono_cfg_add_successor (cfg, bb, cli_addr + 2);
777 case MonoInlineBrTarget:
781 mono_cfg_add_successor (cfg, bb, cli_addr + 5 + i);
782 if (opcode->flow_type == MONO_FLOW_COND_BRANCH)
783 mono_cfg_add_successor (cfg, bb, cli_addr + 5);
785 case MonoInlineSwitch: {
786 gint32 st, target, n;
790 st = cli_addr + 5 + 4 * n;
791 mono_cfg_add_successor (cfg, bb, st);
793 for (i = 0; i < n; i++) {
794 target = read32 (ip) + st;
796 mono_cfg_add_successor (cfg, bb, target);
805 g_assert_not_reached ();
811 * ves_array_element_address:
812 * @this: a pointer to the array object
814 * Returns: the address of an array element.
817 ves_array_element_address (MonoArray *this, ...)
826 g_assert (this != NULL);
830 class = this->obj.vtable->klass;
832 ind = va_arg(ap, int);
833 g_assert (this->bounds != NULL);
835 ind -= this->bounds [0].lower_bound;
836 for (i = 1; i < class->rank; i++) {
837 ind = ind*this->bounds [i].length + va_arg(ap, int) -
838 this->bounds [i].lower_bound;;
841 if (ind >= this->max_length)
842 mono_raise_exception (mono_get_exception_index_out_of_range ());
844 esize = mono_array_element_size (class);
845 ea = (gpointer*)((char*)this->vector + (ind * esize));
846 //printf ("AADDRESS %p %p %d %d %08X\n", this, ea, ind, esize, *(gpointer *)ea);
854 mono_array_new_va (MonoMethod *cm, ...)
856 MonoDomain *domain = mono_domain_get ();
859 guint32 *lower_bounds;
860 int pcount = cm->signature->param_count;
861 int rank = cm->klass->rank;
866 lengths = alloca (sizeof (guint32) * pcount);
867 for (i = 0; i < pcount; ++i)
868 lengths [i] = d = va_arg(ap, int);
870 if (rank == pcount) {
871 /* Only lengths provided. */
874 g_assert (pcount == (rank * 2));
875 /* lower bounds are first. */
876 lower_bounds = lengths;
881 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
884 #define ADD_TREE(t,a) do { t->cli_addr = a; g_ptr_array_add (forest, (t)); } while (0)
885 #define PUSH_TREE(t,k) do { int tt = k; *sp = t; t->svt = tt; t->cli_addr = cli_addr; sp++; } while (0)
887 #define LOCAL_POS(n) (1 + n)
890 #define LOCAL_TYPE(n) ((header)->locals [(n)]->type == MONO_TYPE_BOOLEAN && !(header)->locals [(n)]->byref ? &mono_defaults.int32_class->byval_arg : (header)->locals [(n)])
892 #define LOCAL_TYPE(n) ((header)->locals [(n)])
895 #define ARG_POS(n) (firstarg + n)
896 #define ARG_TYPE(n) ((n) ? (signature)->params [(n) - (signature)->hasthis] : \
897 (signature)->hasthis ? &method->klass->this_arg: (signature)->params [(0)])
901 * replaces all occurences of variable @varnum in @tree with @copy.
904 mono_copy_used_var (MonoFlowGraph *cfg, MBTree *tree, int varnum, MBTree **copy)
910 mono_copy_used_var (cfg, tree->left, varnum, copy);
912 mono_copy_used_var (cfg, tree->right, varnum, copy);
915 case MB_TERM_LDIND_I1:
916 case MB_TERM_LDIND_I2:
917 case MB_TERM_LDIND_I4:
918 case MB_TERM_LDIND_I8:
919 case MB_TERM_LDIND_R4:
920 case MB_TERM_LDIND_R8:
921 if (tree->left->op == MB_TERM_ADDR_L &&
922 tree->left->data.i == varnum) {
924 tree->left->data.i = (*copy)->left->data.i;
928 mono_get_val_sizes (tree->svt, &size, &align);
929 v = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, tree->svt);
931 t1 = mono_ctree_new_leaf (cfg->mp, MB_TERM_ADDR_L);
934 t2 = mono_ctree_new_leaf (cfg->mp, MB_TERM_ADDR_L);
936 t2 = mono_ctree_new (cfg->mp, tree->op, t2, NULL);
938 t2 = mono_ctree_new (cfg->mp, mono_map_store_svt_type (tree->svt), t1, t2);
941 tree->left->data.i = v;
949 * if a variable is modified and there are still referencence
950 * to it on the runtime stack we need to store the value into
951 * a temporary variable and use that value instead of the
955 mono_stack_duplicate_used_var (MonoFlowGraph *cfg, MBTree **stack, MBTree **sp, int varnum)
960 mono_copy_used_var (cfg, *stack, varnum, &res);
968 check_inlining (MonoMethod *method)
970 MonoMethodHeader *header;
971 MonoMethodSignature *signature = method->signature;
972 register const unsigned char *ip, *end;
974 int i, arg_used [256];
978 if (method->inline_info)
979 return method->inline_count;
981 method->inline_info = 1;
983 if (method->wrapper_type != MONO_WRAPPER_NONE)
986 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
987 (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
988 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
989 (method->klass->marshalbyref) ||
990 MONO_TYPE_ISSTRUCT (signature->ret))
993 if (!(header = ((MonoMethodNormal *)method)->header) ||
997 if (header->num_clauses)
1001 end = ip + header->code_size;
1003 for (i = 0; i < 256; i++)
1007 while (!stop && ip < end) {
1056 case CEE_CONV_OVF_I1_UN:
1057 case CEE_CONV_OVF_I2_UN:
1058 case CEE_CONV_OVF_I4_UN:
1059 case CEE_CONV_OVF_I8_UN:
1060 case CEE_CONV_OVF_U1_UN:
1061 case CEE_CONV_OVF_U2_UN:
1062 case CEE_CONV_OVF_U4_UN:
1063 case CEE_CONV_OVF_U8_UN:
1064 case CEE_CONV_OVF_I_UN:
1065 case CEE_CONV_OVF_U_UN:
1077 case CEE_LDELEM_REF:
1085 case CEE_STELEM_REF:
1086 case CEE_CONV_OVF_I1:
1087 case CEE_CONV_OVF_U1:
1088 case CEE_CONV_OVF_I2:
1089 case CEE_CONV_OVF_U2:
1090 case CEE_CONV_OVF_I4:
1091 case CEE_CONV_OVF_U4:
1092 case CEE_CONV_OVF_I8:
1093 case CEE_CONV_OVF_U8:
1098 case CEE_CONV_OVF_I:
1099 case CEE_CONV_OVF_U:
1101 case CEE_ADD_OVF_UN:
1103 case CEE_MUL_OVF_UN:
1105 case CEE_SUB_OVF_UN:
1151 case CEE_CALLVIRT: {
1155 token = read32 (ip);
1158 cm = mono_get_method (method->klass->image, token, NULL);
1164 /* we do not inline functions containing calls to
1165 stack query functions */
1166 if (cm->klass == mono_defaults.stack_frame_class ||
1167 cm->klass == mono_defaults.stack_trace_class)
1176 int an = (*ip) - CEE_LDARG_0;
1179 arg_used [an] = TRUE;
1187 arg_used [*ip] = TRUE;
1199 if (an > 255 || arg_used [an])
1201 arg_used [an] = TRUE;
1215 case CEE_LDVIRTFTN: {
1219 token = read32 (ip);
1222 cm = mono_get_method (method->klass->image, token, NULL);
1246 !(ip [0] == CEE_RET ||
1248 ip [0] == CEE_STLOC_0 &&
1249 ip [1] == CEE_BR_S &&
1251 ip [3] == CEE_LDLOC_0 &&
1252 ip [4] == CEE_RET)))
1255 if (signature->hasthis && arg_used [0])
1256 method->uses_this = 1;
1258 mono_jit_stats.inlineable_methods++;
1260 return method->inline_count = ip - header->code;
1263 return method->inline_count = -1;
1267 create_outstack (MonoFlowGraph *cfg, MonoBBlock *bb, MBTree **stack, int depth)
1269 MonoMemPool *mp = cfg->mp;
1270 MBTree **c = stack, *t1, *t2;
1271 GPtrArray *forest = bb->forest;
1274 g_assert (bb->reached);
1280 g_assert (bb->outdepth == depth);
1284 bb->outdepth = depth;
1285 bb->outstack = mono_mempool_alloc (mp, depth * sizeof (MBTree *));
1287 for (i = 0; i < depth; i++) {
1288 if ((t1 = mono_store_tree (cfg, i, c [i], &t2)))
1290 bb->outstack [i] = t2;
1295 mark_reached (MonoFlowGraph *cfg, MonoBBlock *target, MBTree **stack, int depth)
1297 MonoMemPool *mp = cfg->mp;
1300 if (target->reached)
1303 target->reached = 1;
1310 if (target->instack) {
1311 g_assert (target->indepth == depth);
1315 target->indepth = depth;
1316 target->instack = mono_mempool_alloc (mp, depth * sizeof (MBTree *));
1318 for (i = 0; i < depth; i++) {
1319 target->instack [i] = ctree_create_dup (mp, stack [i]);
1325 #define MARK_REACHED(bb) do { if (!bb->reached) { bb->reached = 1; }} while (0)
1328 * mono_analyze_stack:
1329 * @cfg: control flow graph
1331 * This is the architecture independent part of JIT compilation.
1332 * It creates a forest of trees which can then be fed into the
1333 * architecture dependent code generation.
1335 * The algorithm is from Andi Krall, the same is used in CACAO
1338 mono_analyze_stack (MonoFlowGraph *cfg)
1340 MonoMethod *method = cfg->method;
1341 MonoMemPool *mp = cfg->mp;
1342 MonoBytecodeInfo *bcinfo = cfg->bcinfo;
1343 MonoMethodHeader *header;
1344 MonoMethodSignature *signature;
1347 MBTree **sp, **stack, **arg_sp, **arg_map = NULL, *t1, *t2, *t3;
1348 MonoJitArgumentInfo *arg_info, default_arg_info [10];
1349 register const unsigned char *ip, *end;
1351 int i, j, depth, repeat_count;
1352 int varnum = 0, firstarg = 0;
1353 gboolean repeat, superblock_end;
1354 MonoBBlock *bb, *tbb;
1356 GList *inline_list = NULL;
1357 gboolean tail_recursion;
1359 header = ((MonoMethodNormal *)method)->header;
1360 signature = method->signature;
1361 image = method->klass->image;
1363 /* we add 10 extra slots for method inlining */
1364 maxstack = header->max_stack + 10;
1365 sp = stack = alloca (sizeof (MBTree *) * (maxstack + 1));
1367 /* allocate local variables */
1369 if (header->num_locals) {
1372 for (i = 0; i < header->num_locals; ++i) {
1374 size = mono_type_size (LOCAL_TYPE (i), &align);
1375 mono_map_ldind_type (header->locals [i], &svt);
1376 varnum = arch_allocate_var (cfg, size, align, MONO_LOCALVAR, svt);
1378 cfg->locals_start_index = varnum;
1382 cfg->args_start_index = firstarg = varnum + 1;
1384 /* allocate argument variables */
1386 if (signature->param_count + 1 < 10)
1387 arg_info = default_arg_info;
1389 arg_info = g_new (MonoJitArgumentInfo, signature->param_count + 1);
1391 arch_get_argument_info (signature, signature->param_count, arg_info);
1393 if (signature->hasthis)
1394 arch_allocate_arg (cfg, &arg_info [0], VAL_POINTER);
1396 if (signature->param_count)
1397 for (i = 0; i < signature->param_count; ++i)
1398 arch_allocate_arg (cfg, &arg_info [i + 1], VAL_UNKNOWN);
1400 if (signature->param_count > 9)
1404 for (i = 0; i < header->num_clauses; ++i) {
1405 MonoExceptionClause *clause = &header->clauses [i];
1406 tbb = &cfg->bblocks [bcinfo [clause->handler_offset].block_id];
1407 if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
1408 clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
1409 tbb->instack = mono_mempool_alloc (mp, sizeof (MBTree *));
1411 tbb->instack [0] = t1 = mono_ctree_new_leaf (mp, MB_TERM_EXCEPTION);
1412 t1->data.i = mono_allocate_excvar (cfg);
1413 t1->svt = VAL_POINTER;
1415 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
1416 tbb = &cfg->bblocks [bcinfo [clause->token_or_filter].block_id];
1418 tbb->instack = mono_mempool_alloc (mp, sizeof (MBTree *));
1420 tbb->instack [0] = t1 = mono_ctree_new_leaf (mp, MB_TERM_EXCEPTION);
1421 t1->data.i = mono_allocate_excvar (cfg);
1422 t1->svt = VAL_POINTER;
1425 } else if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
1426 mark_reached (cfg, tbb, NULL, 0);
1428 g_warning ("implement me");
1429 g_assert_not_reached ();
1437 superblock_end = TRUE;
1440 //printf ("START\n");
1441 for (i = 0; i < cfg->block_count; i++) {
1442 bb = &cfg->bblocks [i];
1444 //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);
1446 if (!bb->reached && !superblock_end) {
1447 MonoBBlock *sbb = &cfg->bblocks [i - 1];
1449 g_assert (sbb->outdepth == (sp - stack));
1451 mark_reached (cfg, bb, sbb->outstack, sbb->outdepth);
1456 if (!bb->finished) {
1460 for (j = 0; j < bb->indepth; j++) {
1461 sp [j] = bb->instack [j];
1467 ip = header->code + bb->cli_addr;
1468 end = ip + bb->length;
1470 forest = bb->forest;
1472 superblock_end = FALSE;
1474 tail_recursion = FALSE;
1476 while (inline_list || ip < end) {
1480 MonoInlineInfo *ii = (MonoInlineInfo *)inline_list->data;
1481 if (ip >= ii->end) {
1482 inline_list = g_list_remove_link (inline_list, inline_list);
1484 tail_recursion = FALSE;
1485 image = ii->saved_image;
1487 arg_map = ((MonoInlineInfo *)inline_list->data)->arg_map;
1493 cli_addr = ip - header->code;
1496 //if (inline_list) printf ("INLINE IL%04x OPCODE %s\n", cli_addr, mono_opcode_names [*ip]);
1498 //printf ("%d IL%04x OPCODE %s %d %d %d\n", i, cli_addr, mono_opcode_names [*ip],
1499 //forest->len, superblock_end, sp - stack);
1506 t1 = mono_ctree_new (mp, MB_TERM_THROW, *sp, NULL);
1507 ADD_TREE (t1, cli_addr);
1508 superblock_end = TRUE;
1517 token = read32 (ip);
1520 if (method->wrapper_type != MONO_WRAPPER_NONE)
1521 c = (MonoClass *)mono_method_get_wrapper_data (method, token);
1523 c = mono_class_get (image, token);
1525 t1 = mono_ctree_new_leaf (mp, MB_TERM_NEWOBJ);
1527 t1->svt = VAL_POINTER;
1529 t1 = mono_store_tree (cfg, -1, t1, &t3);
1531 ADD_TREE (t1, cli_addr);
1533 t1 = ctree_create_dup (mp, t3);
1534 t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1535 t2->data.i = sizeof (MonoObject);
1536 t1 = mono_ctree_new (mp, MB_TERM_ADD, t1, t2);
1538 t1 = ctree_create_store (cfg, &c->byval_arg, t1, *sp, FALSE);
1539 ADD_TREE (t1, cli_addr);
1541 PUSH_TREE (t3, VAL_POINTER);
1550 token = read32 (ip);
1554 if (method->wrapper_type != MONO_WRAPPER_NONE)
1555 class = (MonoClass *)mono_method_get_wrapper_data (method, token);
1557 class = mono_class_get (image, token);
1559 t1 = mono_ctree_new (mp, MB_TERM_UNBOX, *sp, NULL);
1560 t1->data.klass = class;
1562 PUSH_TREE (t1, VAL_POINTER);
1569 t1 = mono_ctree_new (mp, MB_TERM_LDLEN, *sp, NULL);
1570 PUSH_TREE (t1, VAL_I32);
1579 token = read32 (ip);
1583 if (method->wrapper_type != MONO_WRAPPER_NONE)
1584 c = (MonoClass *)mono_method_get_wrapper_data (method, token);
1586 c = mono_class_get (image, token);
1587 g_assert (c->valuetype);
1589 t1 = ctree_create_load (cfg, &c->byval_arg, *sp, &svt, FALSE);
1590 PUSH_TREE (t1, svt);
1599 token = read32 (ip);
1603 c = mono_class_get (image, token);
1604 g_assert (c->valuetype);
1606 size = mono_class_value_size (c, NULL);
1608 t1 = mono_ctree_new (mp, MB_TERM_STIND_OBJ, sp [0], sp [1]);
1610 ADD_TREE (t1, cli_addr);
1618 ind = mono_metadata_token_index (read32 (ip));
1621 if (cfg->share_code) {
1622 t1 = mono_ctree_new_leaf (mp, MB_TERM_LDSTR);
1625 o = (MonoObject *) mono_ldstr (cfg->domain, image, ind);
1626 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1630 PUSH_TREE (t1, VAL_POINTER);
1636 MonoClassField *field;
1638 int load_addr = *ip == CEE_LDSFLDA;
1641 token = read32 (ip);
1644 /* need to handle fieldrefs */
1645 field = mono_field_from_token (image, token, &klass);
1648 if (cfg->share_code) {
1649 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1650 t1->data.i = field->offset;
1651 t1 = mono_ctree_new (mp, MB_TERM_LDSFLDA, t1, NULL);
1652 t1->data.klass = klass;
1654 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
1655 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
1656 t1->data.p = (char*)(vt->data) + field->offset;
1662 t1 = ctree_create_load (cfg, field->type, t1, &svt, FALSE);
1665 PUSH_TREE (t1, svt);
1671 MonoClassField *field;
1673 int load_addr = *ip == CEE_LDFLDA;
1676 token = read32 (ip);
1680 /* need to handle fieldrefs */
1681 field = mono_field_from_token (image, token, &klass);
1684 if (klass->marshalbyref) {
1685 t1 = mono_ctree_new (mp, MB_TERM_REMOTE_LDFLDA, sp [0], NULL);
1686 t1->data.fi.klass = klass;
1687 t1->data.fi.field = field;
1689 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1691 if (klass->valuetype)
1692 t1->data.i = field->offset - sizeof (MonoObject);
1694 t1->data.i = field->offset;
1696 t1 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], t1);
1700 t1 = ctree_create_load (cfg, field->type, t1, &svt, FALSE);
1704 PUSH_TREE (t1, svt);
1709 MonoClassField *field;
1713 token = read32 (ip);
1717 /* need to handle fieldrefs */
1718 field = mono_field_from_token (image, token, &klass);
1721 if (cfg->share_code) {
1722 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1723 t1->data.i = field->offset;
1724 t1 = mono_ctree_new (mp, MB_TERM_LDSFLDA, t1, NULL);
1725 t1->data.klass = klass;
1727 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
1728 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
1729 t1->data.p = (char*)(vt->data) + field->offset;
1731 t1 = ctree_create_store (cfg, field->type, t1, *sp, FALSE);
1733 ADD_TREE (t1, cli_addr);
1738 MonoClassField *field;
1742 token = read32 (ip);
1746 /* need to handle fieldrefs */
1747 field = mono_field_from_token (image, token, &klass);
1750 if (klass->marshalbyref) {
1751 t1 = mono_ctree_new (mp, mono_map_remote_stind_type (field->type), sp [0], sp [1]);
1752 t1->data.fi.klass = klass;
1753 t1->data.fi.field = field;
1755 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1756 t1->data.i = klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset;
1757 t1 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], t1);
1758 t1 = mono_ctree_new (mp, MB_TERM_CHECKTHIS, t1, NULL);
1759 t1 = ctree_create_store (cfg, field->type, t1, sp [1], FALSE);
1762 ADD_TREE (t1, cli_addr);
1767 guint32 esize, token;
1770 token = read32 (ip);
1774 class = mono_class_get (image, token);
1776 mono_class_init (class);
1778 esize = mono_class_array_element_size (class);
1780 t1 = mono_ctree_new (mp, MB_TERM_LDELEMA, sp [0], sp [1]);
1782 PUSH_TREE (t1, VAL_POINTER);
1791 t1 = mono_ctree_new_leaf (mp, MB_TERM_BREAK);
1792 ADD_TREE (t1, cli_addr);
1805 t1 = mono_ctree_new (mp, MB_TERM_SWITCH, *sp, NULL);
1806 jt = t1->data.p = mono_alloc_static (sizeof (gpointer) * (n + 2));
1807 st = cli_addr + 5 + 4 * n;
1809 // hack: we store n at position 0
1810 jt [0] = (MonoBBlock *)n;
1812 create_outstack (cfg, bb, stack, sp - stack);
1814 for (k = 1; k <= (n + 1); k++) {
1818 target = read32 (ip) + st;
1821 g_assert (target >= 0 && target <= header->code_size);
1822 g_assert (bcinfo [target].is_block_start);
1823 tbb = &cfg->bblocks [bcinfo [target].block_id];
1824 mark_reached (cfg, tbb, stack, sp - stack);
1828 ADD_TREE (t1, cli_addr);
1833 MonoClass *handle_class;
1834 MonoMethod *next_method;
1837 handle = mono_ldtoken (image, read32 (ip), &handle_class);
1840 if (!cfg->share_code && (*ip == CEE_CALL) && (next_method = mono_get_method (image, read32 (ip+1), NULL)) &&
1841 (next_method->klass == mono_defaults.monotype_class->parent) &&
1842 (strcmp (next_method->name, "GetTypeFromHandle") == 0)) {
1843 MonoClass *tclass = mono_class_from_mono_type (handle);
1844 mono_class_init (tclass);
1846 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1847 t1->data.p = mono_type_get_object (cfg->domain, handle);
1849 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1850 t1->data.p = handle;
1852 PUSH_TREE (t1, VAL_POINTER);
1862 token = read32 (ip);
1865 if (method->wrapper_type != MONO_WRAPPER_NONE)
1866 class = (MonoClass *)mono_method_get_wrapper_data (method, token);
1868 class = mono_class_get (image, token);
1870 if (cfg->share_code) {
1871 t1 = mono_ctree_new (mp, MB_TERM_NEWARR, *sp, NULL);
1875 MonoClass *ac = mono_array_class_get (&class->byval_arg, 1);
1876 MonoVTable *vt = mono_class_vtable (cfg->domain, ac);
1878 t1 = mono_ctree_new (mp, MB_TERM_NEWARR_SPEC, *sp, NULL);
1882 PUSH_TREE (t1, VAL_POINTER);
1890 token = read32 (ip);
1891 class = mono_class_get (image, token);
1895 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1896 t1->data.i = mono_class_value_size (class, NULL);
1897 t1 = mono_ctree_new (mp, MB_TERM_CPSRC, sp [1], t1);
1898 t1 = mono_ctree_new (mp, MB_TERM_CPBLK, sp [0], t1);
1899 ADD_TREE (t1, cli_addr);
1904 MonoMethodSignature *csig;
1906 MBTree *this = NULL;
1913 token = read32 (ip);
1916 cm = mono_get_method (image, token, NULL);
1918 g_assert (!strcmp (cm->name, ".ctor"));
1920 csig = cm->signature;
1921 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
1922 g_assert (csig->hasthis);
1924 arg_sp = sp -= csig->param_count;
1926 if (!cm->klass->inited)
1927 mono_class_init (cm->klass);
1929 if (cm->klass->parent == mono_defaults.array_class) {
1931 this = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1933 } else if (cm->string_ctor) {
1934 static MonoString *string_dummy = NULL;
1937 string_dummy = mono_string_new_wrapper ("dummy");
1940 /* we just pass a dummy as this, it is not used */
1941 this = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1942 this->data.p = string_dummy;
1944 if (cm->klass->valuetype) {
1945 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1946 t1->data.i = mono_class_value_size (cm->klass, NULL);
1947 this = mono_ctree_new (mp, MB_TERM_LOCALLOC, t1, NULL);
1948 this->data.i = TRUE;
1949 } else if (cfg->share_code) {
1950 this = mono_ctree_new_leaf (mp, MB_TERM_NEWOBJ);
1951 this->data.klass = cm->klass;
1953 MonoVTable *vt = mono_class_vtable (cfg->domain, cm->klass);
1954 this = mono_ctree_new_leaf (mp, MB_TERM_NEWOBJ_SPEC);
1958 this->svt = VAL_POINTER;
1960 t1 = mono_store_tree (cfg, -1, this, &this);
1962 ADD_TREE (t1, cli_addr);
1965 if (csig->param_count + 1 < 10)
1966 arg_info = default_arg_info;
1968 arg_info = g_new (MonoJitArgumentInfo, csig->param_count + 1);
1970 frame_size = arch_get_argument_info (csig, csig->param_count, arg_info);
1972 for (k = csig->param_count - 1; k >= 0; k--) {
1973 t1 = mono_ctree_new (mp, mono_map_arg_type (csig->params [k]), arg_sp [k], NULL);
1974 t1->data.arg_info = arg_info [k + 1];
1975 ADD_TREE (t1, cli_addr);
1978 if (newarr || newstr) {
1980 t2 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
1982 t2->data.p = mono_array_new_va;
1984 t2->data.p = arch_create_jit_trampoline (cm);
1987 t1 = mono_ctree_new (mp, MB_TERM_CALL_I4, this, t2);
1988 t1->data.call_info.pad = arg_info [0].pad;
1989 t1->data.call_info.frame_size = frame_size;
1990 t1->svt = VAL_POINTER;
1992 t1 = mono_store_tree (cfg, -1, t1, &t2);
1994 ADD_TREE (t1, cli_addr);
1995 PUSH_TREE (t2, t2->svt);
1999 t2 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
2000 t2->data.p = arch_create_jit_trampoline (cm);
2002 t1 = mono_ctree_new (mp, mono_map_call_type (csig->ret, &svt), this, t2);
2003 t1->data.call_info.pad = arg_info [0].pad;
2004 t1->data.call_info.frame_size = frame_size;
2007 ADD_TREE (t1, cli_addr);
2009 t1 = ctree_create_dup (mp, this);
2011 if (cm->klass->valuetype) {
2012 t2 = ctree_create_load (cfg, &cm->klass->byval_arg, t1, &svt, FALSE);
2013 PUSH_TREE (t2, svt);
2015 PUSH_TREE (t1, t1->svt);
2019 if (csig->param_count > 9)
2026 case CEE_CALLVIRT: {
2027 MonoMethodSignature *csig;
2029 MBTree *ftn, *this = NULL;
2032 int virtual = *ip == CEE_CALLVIRT;
2033 int calli = *ip == CEE_CALLI;
2035 /* fixme: compute this value */
2036 gboolean shared_to_unshared_call = FALSE;
2037 int nargs, vtype_num = 0;
2040 token = read32 (ip);
2043 tail_recursion = FALSE;
2048 if (method->wrapper_type != MONO_WRAPPER_NONE)
2049 csig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
2051 csig = mono_metadata_parse_signature (image, token);
2054 arg_sp = sp -= csig->param_count;
2056 cm = mono_get_method (image, token, NULL);
2059 if (cm->klass == mono_defaults.math_class &&
2060 cm->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
2062 if (!strcmp (cm->name, "Sin")) {
2064 t1 = mono_ctree_new (mp, MB_TERM_SIN, *sp, NULL);
2065 PUSH_TREE (t1, VAL_DOUBLE);
2067 } else if (!strcmp (cm->name, "Cos")) {
2069 t1 = mono_ctree_new (mp, MB_TERM_COS, *sp, NULL);
2070 PUSH_TREE (t1, VAL_DOUBLE);
2072 } else if (!strcmp (cm->name, "Sqrt")) {
2074 t1 = mono_ctree_new (mp, MB_TERM_SQRT, *sp, NULL);
2075 PUSH_TREE (t1, VAL_DOUBLE);
2080 if (cm->string_ctor)
2081 g_assert_not_reached ();
2083 arg_sp = sp -= cm->signature->param_count;
2085 if ((cm->flags & METHOD_ATTRIBUTE_FINAL &&
2086 cm->klass != mono_defaults.object_class) ||
2087 !(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
2091 g_assert (sp >= stack);
2093 if (!calli && mono_jit_inline_code && !virtual && cm->inline_count != -1 &&
2094 cm != method && (cm->inline_info || check_inlining (cm) >= 0)) {
2095 MonoInlineInfo *ii = alloca (sizeof (MonoInlineInfo));
2099 /* avoid recursive inlining */
2100 for (l = inline_list; l; l = l->next) {
2101 if (((MonoInlineInfo *)l->data)->method == cm)
2107 mono_jit_stats.inlined_methods++;
2109 if (cm->signature->hasthis)
2112 args = cm->signature->param_count + cm->signature->hasthis;
2116 ii->saved_image = image;
2117 ii->arg_map = alloca (args * sizeof (MBTree *));
2118 memcpy (ii->arg_map, sp, args * sizeof (MBTree *));
2120 if (cm->signature->hasthis && !cm->uses_this &&
2121 (ii->arg_map [0]->op != MB_TERM_CHECKTHIS)) {
2122 ii->arg_map [0] = mono_ctree_new (mp, MB_TERM_CHECKTHIS,
2123 ii->arg_map [0], NULL);
2124 ADD_TREE (ii->arg_map [0], ii->arg_map [0]->cli_addr);
2127 if (cm->inline_count) {
2128 inline_list = g_list_prepend (inline_list, ii);
2129 ip = ((MonoMethodNormal *)cm)->header->code;
2130 ii->end = ip + cm->inline_count;
2131 arg_map = ii->arg_map;
2132 image = cm->klass->image;
2139 csig = cm->signature;
2141 nargs = csig->param_count;
2143 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
2144 g_assert (!virtual || csig->hasthis);
2146 if (!calli && cm->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
2147 if (cm->klass->parent == mono_defaults.array_class) {
2148 array_rank = cm->klass->rank;
2150 if (cm->name [0] == 'S') /* Set */
2155 if (csig->param_count + 1 < 10)
2156 arg_info = default_arg_info;
2158 arg_info = g_new (MonoJitArgumentInfo, csig->param_count + 1);
2160 frame_size = arch_get_argument_info (csig, nargs, arg_info);
2162 for (k = nargs - 1; k >= 0; k--) {
2163 g_assert (arg_sp [k]);
2164 t1 = mono_ctree_new (mp, mono_map_arg_type (csig->params [k]), arg_sp [k], NULL);
2165 t1->data.arg_info = arg_info [k + 1];
2166 ADD_TREE (t1, arg_sp [k]->cli_addr);
2172 this = mono_ctree_new_leaf (mp, MB_TERM_NOP);
2175 if (MONO_TYPE_ISSTRUCT (csig->ret) && !array_rank) {
2178 size = mono_class_native_size (csig->ret->data.klass, &align);
2180 size = mono_class_value_size (csig->ret->data.klass, &align);
2182 vtype_num = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, VAL_UNKNOWN);
2187 t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2188 t2->data.p = ves_array_element_address;
2190 t1 = mono_ctree_new (mp, MB_TERM_CALL_I4, this, t2);
2191 t1->data.call_info.vtype_num = vtype_num;
2192 t1->data.call_info.frame_size = frame_size;
2193 t1->data.call_info.pad = arg_info [0].pad;
2194 t1->svt = VAL_POINTER;
2196 t1 = mono_store_tree (cfg, -1, t1, &t2);
2198 ADD_TREE (t1, cli_addr);
2200 if (cm->name [0] == 'G') { /* Get */
2201 t1 = mono_ctree_new (mp, mono_map_ldind_type (csig->ret, &svt), t2, NULL);
2203 PUSH_TREE (t1, t1->svt);
2204 } else if (cm->name [0] == 'S') { /* Set */
2205 t1 = ctree_create_store (cfg, csig->params [nargs], t2, arg_sp [nargs], FALSE);
2206 ADD_TREE (t1, cli_addr);
2207 } else if (cm->name [0] == 'A') { /* Address */
2208 PUSH_TREE (t2, t1->svt);
2210 g_assert_not_reached ();
2217 } else if (virtual || (csig->hasthis &&
2218 !(cm->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
2219 (cm->klass->marshalbyref || shared_to_unshared_call))) {
2221 mono_class_init (cm->klass);
2223 if (cm->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
2224 t2 = mono_ctree_new_leaf (mp, MB_TERM_INTF_ADDR);
2226 t2 = mono_ctree_new_leaf (mp, MB_TERM_VFUNC_ADDR);
2231 t2 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
2232 t2->data.p = arch_create_jit_trampoline (cm);
2236 t1 = mono_ctree_new (mp, mono_map_call_type (csig->ret, &svt), this, t2);
2237 t1->data.call_info.vtype_num = vtype_num;
2238 t1->data.call_info.frame_size = frame_size;
2239 t1->data.call_info.pad = arg_info [0].pad;
2242 if (csig->ret->type != MONO_TYPE_VOID) {
2245 ADD_TREE (t1, cli_addr);
2246 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2247 t1->data.i = vtype_num;
2248 PUSH_TREE (t1, VAL_POINTER);
2250 t1 = mono_store_tree (cfg, -1, t1, &t2);
2252 ADD_TREE (t1, cli_addr);
2253 PUSH_TREE (t2, t2->svt);
2256 ADD_TREE (t1, cli_addr);
2259 if (csig->param_count > 9)
2268 token = read32 (ip);
2271 c = mono_class_get (image, token);
2273 mono_class_init (c);
2275 t1 = mono_ctree_new (mp, MB_TERM_ISINST, *sp, NULL);
2278 PUSH_TREE (t1, VAL_POINTER);
2283 case CEE_CASTCLASS: {
2287 token = read32 (ip);
2290 c = mono_class_get (image, token);
2292 mono_class_init (c);
2294 t1 = mono_ctree_new (mp, MB_TERM_CASTCLASS, *sp, NULL);
2297 PUSH_TREE (t1, VAL_POINTER);
2302 case CEE_LDC_I4_S: {
2304 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2305 t1->data.i = *(const gint8 *)ip;
2307 PUSH_TREE (t1, VAL_I32);
2312 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2313 t1->data.i = read32 (ip);
2315 PUSH_TREE (t1, VAL_I32);
2327 case CEE_LDC_I4_8: {
2328 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2329 t1->data.i = (*ip) - CEE_LDC_I4_0;
2331 PUSH_TREE (t1, VAL_I32);
2335 //fixme: don't know if this is portable ?
2337 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2339 PUSH_TREE (t1, VAL_POINTER);
2344 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I8);
2345 t1->data.l = read64 (ip);
2347 PUSH_TREE (t1, VAL_I64);
2351 float *f = mono_alloc_static (sizeof (float));
2353 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_R4);
2357 PUSH_TREE (t1, VAL_DOUBLE);
2361 double *d = mono_alloc_static (sizeof (double));
2363 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_R8);
2367 PUSH_TREE (t1, VAL_DOUBLE);
2374 int n = (*ip) - CEE_LDLOC_0;
2377 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2378 t1->data.i = LOCAL_POS (n);
2379 if (!MONO_TYPE_ISSTRUCT (LOCAL_TYPE (n)))
2380 t1 = ctree_create_load (cfg, LOCAL_TYPE (n), t1, &svt, FALSE);
2381 PUSH_TREE (t1, svt);
2387 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2388 t1->data.i = LOCAL_POS (*ip);
2389 if (!MONO_TYPE_ISSTRUCT (LOCAL_TYPE (*ip)))
2390 t1 = ctree_create_load (cfg, LOCAL_TYPE (*ip), t1, &svt, FALSE);
2393 PUSH_TREE (t1, svt);
2396 case CEE_LDLOCA_S: {
2399 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2400 t1->data.i = LOCAL_POS (*ip);
2401 VARINFO (cfg, t1->data.i).isvolatile = 1;
2403 PUSH_TREE (t1, VAL_POINTER);
2410 int n = (*ip) - CEE_STLOC_0;
2414 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2415 t1->data.i = LOCAL_POS (n);
2417 if ((t2 = mono_stack_duplicate_used_var (cfg, stack, sp, t1->data.i)))
2418 ADD_TREE (t2, cli_addr);
2420 t1 = ctree_create_store (cfg, LOCAL_TYPE (n), t1, *sp, FALSE);
2421 ADD_TREE (t1, cli_addr);
2428 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2429 t1->data.i = LOCAL_POS (*ip);
2430 if ((t2 = mono_stack_duplicate_used_var (cfg, stack, sp, t1->data.i)))
2431 ADD_TREE (t2, cli_addr);
2433 t1 = ctree_create_store (cfg, LOCAL_TYPE (*ip), t1, *sp, FALSE);
2435 ADD_TREE (t1, cli_addr);
2442 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4)
2443 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i + sp [1]->data.i);
2445 t1 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], sp [1]);
2446 PUSH_TREE (t1, sp [0]->svt);
2453 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4)
2454 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i - sp [1]->data.i);
2456 t1 = mono_ctree_new (mp, MB_TERM_SUB, sp [0], sp [1]);
2457 PUSH_TREE (t1, sp [0]->svt);
2464 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4)
2465 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i & sp [1]->data.i);
2467 t1 = mono_ctree_new (mp, MB_TERM_AND, sp [0], sp [1]);
2468 PUSH_TREE (t1, sp [0]->svt);
2475 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4)
2476 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i | sp [1]->data.i);
2478 t1 = mono_ctree_new (mp, MB_TERM_OR, sp [0], sp [1]);
2479 PUSH_TREE (t1, sp [0]->svt);
2486 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4)
2487 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i ^ sp [1]->data.i);
2489 t1 = mono_ctree_new (mp, MB_TERM_XOR, sp [0], sp [1]);
2490 PUSH_TREE (t1, sp [0]->svt);
2497 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4) {
2498 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i * sp [1]->data.i);
2499 PUSH_TREE (t1, sp [0]->svt);
2501 MAKE_SPILLED_BI_ALU1 (MUL, sp [0], sp [1])
2509 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4
2510 && (sp[1]->data.i != 0)
2511 && ((sp[0]->data.i != 0x080000000) || (sp[1]->data.i != -1))) {
2512 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i / sp [1]->data.i);
2513 PUSH_TREE (t1, sp [0]->svt);
2515 MAKE_SPILLED_BI_ALU1 (DIV, sp [0], sp [1])
2523 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4) {
2524 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i % sp [1]->data.i);
2525 PUSH_TREE (t1, sp [0]->svt);
2527 MAKE_SPILLED_BI_ALU1 (REM, sp [0], sp [1])
2535 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4) {
2536 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i << sp [1]->data.i);
2537 PUSH_TREE (t1, sp [0]->svt);
2539 MAKE_SPILLED_BI_ALU1 (SHL, sp [0], sp [1])
2547 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4) {
2548 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i >> sp [1]->data.i);
2549 PUSH_TREE (t1, sp [0]->svt);
2551 MAKE_SPILLED_BI_ALU1 (SHR, sp [0], sp [1])
2556 MAKE_BI_ALU (ADD_OVF)
2557 MAKE_BI_ALU (ADD_OVF_UN)
2558 MAKE_BI_ALU (SUB_OVF)
2559 MAKE_BI_ALU (SUB_OVF_UN)
2560 MAKE_SPILLED_BI_ALU (SHR_UN)
2561 MAKE_SPILLED_BI_ALU (MUL_OVF)
2562 MAKE_SPILLED_BI_ALU (MUL_OVF_UN)
2563 MAKE_SPILLED_BI_ALU (DIV_UN)
2564 MAKE_SPILLED_BI_ALU (REM_UN)
2566 MAKE_LDIND (LDIND_I1, MB_TERM_LDIND_I1, VAL_I32)
2567 MAKE_LDIND (LDIND_U1, MB_TERM_LDIND_U1, VAL_I32)
2568 MAKE_LDIND (LDIND_I2, MB_TERM_LDIND_I2, VAL_I32)
2569 MAKE_LDIND (LDIND_U2, MB_TERM_LDIND_U2, VAL_I32)
2570 MAKE_LDIND (LDIND_I, MB_TERM_LDIND_I4, VAL_I32)
2571 MAKE_LDIND (LDIND_I4, MB_TERM_LDIND_I4, VAL_I32)
2572 MAKE_LDIND (LDIND_REF, MB_TERM_LDIND_REF, VAL_POINTER)
2573 MAKE_LDIND (LDIND_U4, MB_TERM_LDIND_U4, VAL_I32)
2574 MAKE_LDIND (LDIND_I8, MB_TERM_LDIND_I8, VAL_I64)
2575 MAKE_LDIND (LDIND_R4, MB_TERM_LDIND_R4, VAL_DOUBLE)
2576 MAKE_LDIND (LDIND_R8, MB_TERM_LDIND_R8, VAL_DOUBLE)
2578 MAKE_STIND (STIND_I1, MB_TERM_STIND_I1)
2579 MAKE_STIND (STIND_I2, MB_TERM_STIND_I2)
2580 MAKE_STIND (STIND_I, MB_TERM_STIND_I4)
2581 MAKE_STIND (STIND_I4, MB_TERM_STIND_I4)
2582 MAKE_STIND (STIND_I8, MB_TERM_STIND_I8)
2583 MAKE_STIND (STIND_R4, MB_TERM_STIND_R4)
2584 MAKE_STIND (STIND_R8, MB_TERM_STIND_R8)
2585 MAKE_STIND (STIND_REF, MB_TERM_STIND_REF)
2587 MAKE_LDELEM (LDELEM_I1, MB_TERM_LDIND_I1, VAL_I32, 1)
2588 MAKE_LDELEM (LDELEM_U1, MB_TERM_LDIND_U1, VAL_I32, 1)
2589 MAKE_LDELEM (LDELEM_I2, MB_TERM_LDIND_I2, VAL_I32, 2)
2590 MAKE_LDELEM (LDELEM_U2, MB_TERM_LDIND_U2, VAL_I32, 2)
2591 MAKE_LDELEM (LDELEM_I, MB_TERM_LDIND_I4, VAL_I32, 4)
2592 MAKE_LDELEM (LDELEM_I4, MB_TERM_LDIND_I4, VAL_I32, 4)
2593 MAKE_LDELEM (LDELEM_REF, MB_TERM_LDIND_REF, VAL_POINTER, sizeof (gpointer))
2594 MAKE_LDELEM (LDELEM_U4, MB_TERM_LDIND_U4, VAL_I32, 4)
2595 MAKE_LDELEM (LDELEM_I8, MB_TERM_LDIND_I8, VAL_I64, 8)
2596 MAKE_LDELEM (LDELEM_R4, MB_TERM_LDIND_R4, VAL_DOUBLE, 4)
2597 MAKE_LDELEM (LDELEM_R8, MB_TERM_LDIND_R8, VAL_DOUBLE, 8)
2599 MAKE_STELEM (STELEM_I1, MB_TERM_STIND_I1, 1)
2600 MAKE_STELEM (STELEM_I2, MB_TERM_STIND_I2, 2)
2601 MAKE_STELEM (STELEM_I4, MB_TERM_STIND_I4, 4)
2602 MAKE_STELEM (STELEM_I, MB_TERM_STIND_I4, 4)
2603 MAKE_STELEM (STELEM_REF, MB_TERM_STIND_REF, sizeof (gpointer))
2604 MAKE_STELEM (STELEM_I8, MB_TERM_STIND_I8, 8)
2605 MAKE_STELEM (STELEM_R4, MB_TERM_STIND_R4, 4)
2606 MAKE_STELEM (STELEM_R8, MB_TERM_STIND_R8, 8)
2611 if (sp [0]->op == MB_TERM_CONST_I4)
2612 t1 = mono_ctree_new_icon4 (mp, -sp [0]->data.i);
2614 t1 = mono_ctree_new (mp, MB_TERM_NEG, sp [0], NULL);
2615 PUSH_TREE (t1, sp [0]->svt);
2621 if (sp [0]->op == MB_TERM_CONST_I4)
2622 t1 = mono_ctree_new_icon4 (mp, ~sp [0]->data.i);
2624 t1 = mono_ctree_new (mp, MB_TERM_NOT, sp [0], NULL);
2625 PUSH_TREE (t1, sp [0]->svt);
2631 int br_s = (*ip == CEE_BR_S);
2635 target = cli_addr + 2 + (signed char) *ip;
2637 target = cli_addr + 5 + (gint32) read32(ip);
2639 g_assert (target >= 0 && target <= header->code_size);
2640 g_assert (bcinfo [target].is_block_start);
2641 tbb = &cfg->bblocks [bcinfo [target].block_id];
2642 create_outstack (cfg, bb, stack, sp - stack);
2643 mark_reached (cfg, tbb, bb->outstack, bb->outdepth);
2645 t1 = mono_ctree_new_leaf (mp, MB_TERM_BR);
2647 ADD_TREE (t1, cli_addr);
2654 superblock_end = TRUE;
2661 token = read32 (ip);
2664 cm = mono_get_method (method->klass->image, token, NULL);
2667 t1 = mono_ctree_new_leaf (mp, MB_TERM_JMP);
2668 /* fixme: our magic trampoline code does not work in this case,
2669 * so I need to compile the method immediately */
2670 t1->data.p = mono_compile_method (cm);;
2672 ADD_TREE (t1, cli_addr);
2679 int leave_s = (*ip == CEE_LEAVE_S);
2683 target = cli_addr + 2 + (signed char) *ip;
2685 target = cli_addr + 5 + (gint32) read32(ip);
2687 g_assert (target >= 0 && target <= header->code_size);
2688 g_assert (bcinfo [target].is_block_start);
2689 tbb = &cfg->bblocks [bcinfo [target].block_id];
2691 /* empty the stack */
2692 while (sp != stack) {
2694 t1 = mono_ctree_new (mp, MB_TERM_POP, *sp, NULL);
2695 ADD_TREE (t1, cli_addr);
2698 mark_reached (cfg, tbb, NULL, 0);
2700 /* fixme: fault handler */
2702 if ((hb = mono_find_final_block (cfg, cli_addr, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
2703 mark_reached (cfg, hb, NULL, 0);
2704 t1 = mono_ctree_new_leaf (mp, MB_TERM_HANDLER);
2706 ADD_TREE (t1, cli_addr);
2709 /* check if we leave a catch handler, if so we have to
2710 * rethrow ThreadAbort exceptions */
2711 for (k = 0; k < header->num_clauses; ++k) {
2712 MonoExceptionClause *clause = &header->clauses [k];
2713 if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE &&
2714 MONO_OFFSET_IN_HANDLER (clause, cli_addr)) {
2715 t1 = mono_ctree_new_leaf (mp, MB_TERM_RETHROW_ABORT);
2716 t1->data.i = mono_allocate_excvar (cfg);
2717 ADD_TREE (t1, cli_addr);
2722 t1 = mono_ctree_new_leaf (mp, MB_TERM_BR);
2724 ADD_TREE (t1, cli_addr);
2731 superblock_end = TRUE;
2748 case CEE_BRTRUE_S: {
2750 int near_jump = *ip == CEE_BRTRUE_S;
2754 t1 = mono_ctree_new (mp, MB_TERM_BRTRUE, sp [0], NULL);
2757 target = cli_addr + 2 + (signed char) *ip;
2759 target = cli_addr + 5 + (gint32) read32 (ip);
2761 g_assert (target >= 0 && target <= header->code_size);
2762 g_assert (bcinfo [target].is_block_start);
2763 tbb = &cfg->bblocks [bcinfo [target].block_id];
2764 create_outstack (cfg, bb, stack, sp - stack);
2765 mark_reached (cfg, tbb, bb->outstack, bb->outdepth);
2768 ip += near_jump ? 1: 4;
2769 ADD_TREE (t1, cli_addr);
2773 case CEE_BRFALSE_S: {
2775 int near_jump = *ip == CEE_BRFALSE_S;
2779 t1 = mono_ctree_new (mp, MB_TERM_BRFALSE, sp [0], NULL);
2782 target = cli_addr + 2 + (signed char) *ip;
2784 target = cli_addr + 5 + (gint32) read32 (ip);
2786 g_assert (target >= 0 && target <= header->code_size);
2787 g_assert (bcinfo [target].is_block_start);
2788 tbb = &cfg->bblocks [bcinfo [target].block_id];
2789 create_outstack (cfg, bb, stack, sp - stack);
2790 mark_reached (cfg, tbb, bb->outstack, bb->outdepth);
2793 ip += near_jump ? 1: 4;
2794 ADD_TREE (t1, cli_addr);
2798 MonoType *ret = signature->ret;
2802 if (ret->type != MONO_TYPE_VOID) {
2804 if (MONO_TYPE_ISSTRUCT (ret)) {
2806 t1 = mono_ctree_new (mp, MB_TERM_RET_OBJ, *sp, NULL);
2807 t1->data.i = mono_class_value_size (ret->data.klass, &align);
2809 t1 = mono_ctree_new (mp, MB_TERM_RET, *sp, NULL);
2812 t1 = mono_ctree_new_leaf (mp, MB_TERM_RET_VOID);
2815 t1->last_instr = (ip == (header->code + header->code_size));
2817 ADD_TREE (t1, cli_addr);
2820 g_warning ("more values on stack at %s IL_%04x: %d",
2821 mono_method_full_name (method, TRUE),
2822 ip - header->code, sp - stack);
2823 mono_print_ctree (cfg, sp [-1]);
2826 superblock_end = TRUE;
2829 case CEE_ENDFINALLY: {
2832 t1 = mono_ctree_new_leaf (mp, MB_TERM_ENDFINALLY);
2833 ADD_TREE (t1, cli_addr);
2834 t1->last_instr = FALSE;
2836 g_assert (sp == stack);
2837 superblock_end = TRUE;
2844 int n = (*ip) - CEE_LDARG_0;
2851 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2852 t1->data.i = ARG_POS (n);
2853 if (!MONO_TYPE_ISSTRUCT (ARG_TYPE (n)))
2854 t1 = ctree_create_load (cfg, ARG_TYPE (n), t1, &svt, TRUE);
2856 PUSH_TREE (t1, svt);
2865 *sp = arg_map [*ip];
2868 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2869 t1->data.i = ARG_POS (*ip);
2870 if (!MONO_TYPE_ISSTRUCT (ARG_TYPE (*ip)))
2871 t1 = ctree_create_load (cfg, ARG_TYPE (*ip), t1, &svt, TRUE);
2872 PUSH_TREE (t1, svt);
2877 case CEE_LDARGA_S: {
2879 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2880 t1->data.i = ARG_POS (*ip);
2881 PUSH_TREE (t1, VAL_POINTER);
2889 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2890 t1->data.i = ARG_POS (*ip);
2891 t1 = ctree_create_store (cfg, ARG_TYPE (*ip), t1, *sp, TRUE);
2893 ADD_TREE (t1, cli_addr);
2901 /* fixme: maybe we should add more of these optimisations */
2902 if (sp [-1]->op == MB_TERM_CONST_I4) {
2904 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2905 t1->data.i = sp [-1]->data.i;
2906 PUSH_TREE (t1, VAL_I32);
2911 vnum = mono_allocate_intvar (cfg, sp - stack, sp [0]->svt);
2912 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2915 t2 = mono_ctree_new (mp, mono_map_store_svt_type (sp [0]->svt), t1, sp [0]);
2916 t2->svt = sp [0]->svt;
2917 ADD_TREE (t2, cli_addr);
2919 t1 = ctree_create_dup (mp, t2);
2920 PUSH_TREE (t1, t1->svt);
2921 t1 = ctree_create_dup (mp, t1);
2922 PUSH_TREE (t1, t1->svt);
2930 t1 = mono_ctree_new (mp, MB_TERM_POP, *sp, NULL);
2931 ADD_TREE (t1, cli_addr);
2935 case CEE_CKFINITE: {
2940 /* this instr. can throw exceptions as side effect,
2941 * so we cant eliminate dead code which contains CKFINITE opdodes.
2942 * Spilling to memory makes sure that we always perform
2944 vnum = mono_allocate_intvar (cfg, sp - stack, sp [0]->svt);
2945 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2948 t2 = mono_ctree_new (mp, MB_TERM_CKFINITE, *sp, NULL);
2950 t2 = mono_ctree_new (mp, mono_map_store_svt_type (sp [0]->svt), t1, t2);
2951 t2->svt = sp [0]->svt;
2952 ADD_TREE (t2, cli_addr);
2954 t1 = ctree_create_dup (mp, t2);
2955 PUSH_TREE (t1, t1->svt);
2961 if (sp [0]->op == MB_TERM_CONST_I4)
2962 t1 = mono_ctree_new_icon4 (mp, (guint8)sp [0]->data.i);
2964 t1 = mono_ctree_new (mp, MB_TERM_CONV_U1, *sp, NULL);
2965 PUSH_TREE (t1, VAL_I32);
2970 if (sp [0]->op == MB_TERM_CONST_I4)
2971 t1 = mono_ctree_new_icon4 (mp, (gint8)sp [0]->data.i);
2973 t1 = mono_ctree_new (mp, MB_TERM_CONV_I1, *sp, NULL);
2974 PUSH_TREE (t1, VAL_I32);
2979 if (sp [0]->op == MB_TERM_CONST_I4)
2980 t1 = mono_ctree_new_icon4 (mp, (guint16)sp [0]->data.i);
2982 t1 = mono_ctree_new (mp, MB_TERM_CONV_U2, *sp, NULL);
2983 PUSH_TREE (t1, VAL_I32);
2988 if (sp [0]->op == MB_TERM_CONST_I4)
2989 t1 = mono_ctree_new_icon4 (mp, (gint16)sp [0]->data.i);
2991 t1 = mono_ctree_new (mp, MB_TERM_CONV_I2, *sp, NULL);
2992 PUSH_TREE (t1, VAL_I32);
2998 if (sp [0]->op == MB_TERM_CONST_I4)
3001 t1 = mono_ctree_new (mp, MB_TERM_CONV_I4, *sp, NULL);
3002 PUSH_TREE (t1, VAL_I32);
3008 if (sp [0]->op == MB_TERM_CONST_I4)
3011 t1 = mono_ctree_new (mp, MB_TERM_CONV_U4, *sp, NULL);
3012 PUSH_TREE (t1, VAL_I32);
3017 t1 = mono_ctree_new (mp, MB_TERM_CONV_I8, *sp, NULL);
3018 PUSH_TREE (t1, VAL_I64);
3023 t1 = mono_ctree_new (mp, MB_TERM_CONV_U8, *sp, NULL);
3024 PUSH_TREE (t1, VAL_I64);
3029 t1 = mono_ctree_new (mp, MB_TERM_CONV_R8, *sp, NULL);
3030 PUSH_TREE (t1, VAL_DOUBLE);
3035 t1 = mono_ctree_new (mp, MB_TERM_CONV_R4, *sp, NULL);
3036 PUSH_TREE (t1, VAL_DOUBLE);
3041 t1 = mono_ctree_new (mp, MB_TERM_CONV_R_UN, *sp, NULL);
3042 PUSH_TREE (t1, VAL_DOUBLE);
3044 case CEE_CONV_OVF_I:
3045 case CEE_CONV_OVF_I4:
3048 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I4, *sp, NULL);
3049 PUSH_TREE (t1, VAL_I32);
3051 case CEE_CONV_OVF_I_UN:
3052 case CEE_CONV_OVF_I4_UN:
3055 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I4_UN, *sp, NULL);
3056 PUSH_TREE (t1, VAL_I32);
3058 case CEE_CONV_OVF_U:
3059 case CEE_CONV_OVF_U4:
3062 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U4, *sp, NULL);
3063 PUSH_TREE (t1, VAL_I32);
3065 case CEE_CONV_OVF_I1:
3068 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I1, *sp, NULL);
3069 PUSH_TREE (t1, VAL_I32);
3071 case CEE_CONV_OVF_I1_UN:
3074 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I1_UN, *sp, NULL);
3075 PUSH_TREE (t1, VAL_I32);
3077 case CEE_CONV_OVF_U1_UN:
3080 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U1_UN, *sp, NULL);
3081 PUSH_TREE (t1, VAL_I32);
3083 case CEE_CONV_OVF_U1:
3086 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U1, *sp, NULL);
3087 PUSH_TREE (t1, VAL_I32);
3089 case CEE_CONV_OVF_I2:
3092 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I2, *sp, NULL);
3093 PUSH_TREE (t1, VAL_I32);
3095 case CEE_CONV_OVF_U2_UN:
3098 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U2_UN, *sp, NULL);
3099 PUSH_TREE (t1, VAL_I32);
3101 case CEE_CONV_OVF_U2:
3104 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U2, *sp, NULL);
3105 PUSH_TREE (t1, VAL_I32);
3107 case CEE_CONV_OVF_I2_UN:
3110 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I2_UN, *sp, NULL);
3111 PUSH_TREE (t1, VAL_I32);
3113 case CEE_CONV_OVF_U8:
3116 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U8, *sp, NULL);
3117 PUSH_TREE (t1, VAL_I32);
3119 case CEE_CONV_OVF_U_UN:
3120 case CEE_CONV_OVF_U4_UN:
3121 // fixme: raise exceptions ?
3124 t1 = mono_ctree_new (mp, MB_TERM_CONV_I4, *sp, NULL);
3125 PUSH_TREE (t1, VAL_I32);
3127 case CEE_CONV_OVF_I8_UN:
3128 case CEE_CONV_OVF_U8_UN: /* FIXME: slightly incorrect, but non worth fixing the corner cases in the old jit */
3131 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I8_UN, *sp, NULL);
3132 PUSH_TREE (t1, VAL_I64);
3134 case MONO_CUSTOM_PREFIX: {
3138 case CEE_MONO_FUNC1: {
3139 MonoMarshalConv conv;
3147 t1 = mono_ctree_new (mp, MB_TERM_FUNC1, *sp, NULL);
3150 case MONO_MARSHAL_CONV_STR_LPWSTR:
3151 t1->data.p = mono_string_to_utf16;
3153 case MONO_MARSHAL_CONV_LPSTR_STR:
3154 t1->data.p = mono_string_new_wrapper;
3156 case MONO_MARSHAL_CONV_STR_LPTSTR:
3157 case MONO_MARSHAL_CONV_STR_LPSTR:
3158 t1->data.p = mono_string_to_utf8;
3160 case MONO_MARSHAL_CONV_STR_BSTR:
3161 t1->data.p = mono_string_to_bstr;
3163 case MONO_MARSHAL_CONV_STR_TBSTR:
3164 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
3165 t1->data.p = mono_string_to_ansibstr;
3167 case MONO_MARSHAL_CONV_SB_LPSTR:
3168 t1->data.p = mono_string_builder_to_utf8;
3170 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
3171 t1->data.p = mono_array_to_savearray;
3173 case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
3174 t1->data.p = mono_array_to_lparray;
3176 case MONO_MARSHAL_CONV_DEL_FTN:
3177 t1->data.p = mono_delegate_to_ftnptr;
3179 case MONO_MARSHAL_CONV_STRARRAY_STRLPARRAY:
3180 t1->data.p = mono_marshal_string_array;
3183 g_assert_not_reached ();
3185 PUSH_TREE (t1, VAL_POINTER);
3188 case CEE_MONO_PROC2: {
3189 MonoMarshalConv conv;
3195 t1 = mono_ctree_new (mp, MB_TERM_PROC2, sp [0], sp [1]);
3198 case MONO_MARSHAL_CONV_LPSTR_SB:
3199 t1->data.p = mono_string_utf8_to_builder;
3201 case MONO_MARSHAL_FREE_ARRAY:
3202 t1->data.p = mono_marshal_free_array;
3205 g_assert_not_reached ();
3207 ADD_TREE (t1, cli_addr);
3210 case CEE_MONO_PROC3: {
3211 MonoMarshalConv conv;
3218 t1 = mono_ctree_new (mp, MB_TERM_CPSRC, sp [1], sp [2]);
3219 t1 = mono_ctree_new (mp, MB_TERM_PROC3, sp [0], t1);
3222 case MONO_MARSHAL_CONV_STR_BYVALSTR:
3223 t1->data.p = mono_string_to_byvalstr;
3225 case MONO_MARSHAL_CONV_STR_BYVALWSTR:
3226 t1->data.p = mono_string_to_byvalwstr;
3229 g_assert_not_reached ();
3232 ADD_TREE (t1, cli_addr);
3235 case CEE_MONO_FREE: {
3239 t1 = mono_ctree_new (mp, MB_TERM_FREE, *sp, NULL);
3240 ADD_TREE (t1, cli_addr);
3243 case CEE_MONO_OBJADDR: {
3247 t1 = mono_ctree_new (mp, MB_TERM_OBJADDR, *sp, NULL);
3248 PUSH_TREE (t1, VAL_POINTER);
3251 case CEE_MONO_VTADDR: {
3255 t1 = mono_ctree_new (mp, MB_TERM_VTADDR, *sp, NULL);
3256 PUSH_TREE (t1, VAL_POINTER);
3259 case CEE_MONO_LDPTR: {
3263 token = read32 (ip);
3266 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
3267 t1->data.p = mono_method_get_wrapper_data (method, token);
3269 PUSH_TREE (t1, VAL_POINTER);
3272 case CEE_MONO_NEWOBJ: {
3277 token = read32 (ip);
3280 class = (MonoClass *)mono_method_get_wrapper_data (method, token);
3282 t1 = mono_ctree_new_leaf (mp, MB_TERM_NEWOBJ);
3284 PUSH_TREE (t1, VAL_POINTER);
3288 case CEE_MONO_RETOBJ: {
3289 MonoType *ret = signature->ret;
3294 token = read32 (ip);
3297 class = (MonoClass *)mono_method_get_wrapper_data (method, token);
3301 g_assert (MONO_TYPE_ISSTRUCT (ret));
3303 t1 = ctree_create_load (cfg, &class->byval_arg, *sp, &svt, FALSE);
3304 t1 = mono_ctree_new (mp, MB_TERM_RET_OBJ, t1, NULL);
3306 if (signature->pinvoke)
3307 t1->data.i = mono_class_native_size (ret->data.klass, NULL);
3309 t1->data.i = mono_class_value_size (ret->data.klass, NULL);
3311 t1->last_instr = (ip == (header->code + header->code_size));
3313 ADD_TREE (t1, cli_addr);
3316 g_warning ("more values on stack at %s IL_%04x: %d",
3317 mono_method_full_name (method, TRUE),
3318 ip - header->code, sp - stack);
3319 mono_print_ctree (cfg, sp [-1]);
3322 superblock_end = TRUE;
3326 g_error ("Unimplemented opcode at IL_%04x "
3327 "%02x %02x", ip - header->code, MONO_CUSTOM_PREFIX, *ip);
3335 case CEE_ENDFILTER: {
3339 t1 = mono_ctree_new (mp, MB_TERM_ENDFILTER, *sp, NULL);
3340 ADD_TREE (t1, cli_addr);
3341 t1->last_instr = FALSE;
3343 g_assert (sp == stack);
3344 superblock_end = TRUE;
3353 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3354 t1->data.i = LOCAL_POS (n);
3355 if (!MONO_TYPE_ISSTRUCT (LOCAL_TYPE (n)))
3356 t1 = ctree_create_load (cfg, LOCAL_TYPE (n), t1, &svt, FALSE);
3359 PUSH_TREE (t1, svt);
3365 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3366 t1->data.i = LOCAL_POS (read16 (ip));
3367 VARINFO (cfg, t1->data.i).isvolatile = 1;
3369 PUSH_TREE (t1, VAL_POINTER);
3376 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3377 t1->data.i = LOCAL_POS (read16 (ip));
3378 if ((t2 = mono_stack_duplicate_used_var (cfg, stack, sp, t1->data.i)))
3379 ADD_TREE (t2, cli_addr);
3381 t1 = ctree_create_store (cfg, LOCAL_TYPE (read16 (ip)), t1, *sp, FALSE);
3383 ADD_TREE (t1, cli_addr);
3391 arg_pos = read16 (ip);
3394 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3395 t1->data.i = ARG_POS (arg_pos);
3396 t1 = ctree_create_store (cfg, ARG_TYPE (arg_pos), t1, *sp, TRUE);
3397 ADD_TREE (t1, cli_addr);
3409 t1 = mono_ctree_new_leaf (mp, MB_TERM_RETHROW);
3410 t1->data.i = mono_allocate_excvar (cfg);
3411 ADD_TREE (t1, cli_addr);
3418 token = read32 (ip);
3421 if (method->wrapper_type != MONO_WRAPPER_NONE)
3422 cm = (MonoMethod *)mono_method_get_wrapper_data (method, token);
3424 cm = mono_get_method (image, token, NULL);
3428 t1 = mono_ctree_new_leaf (mp, MB_TERM_LDFTN);
3430 PUSH_TREE (t1, VAL_POINTER);
3433 case CEE_LDVIRTFTN: {
3437 token = read32 (ip);
3441 cm = mono_get_method (image, token, NULL);
3444 if (cm->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
3445 t2 = mono_ctree_new_leaf (mp, MB_TERM_INTF_ADDR);
3447 t2 = mono_ctree_new_leaf (mp, MB_TERM_VFUNC_ADDR);
3451 t1 = mono_ctree_new (mp, MB_TERM_LDVIRTFTN, *sp, t2);
3453 PUSH_TREE (t1, VAL_POINTER);
3462 token = read32 (ip);
3463 class = mono_class_get (image, token);
3467 t1 = mono_ctree_new (mp, MB_TERM_INITOBJ, *sp, NULL);
3468 t1->data.i = mono_class_value_size (class, NULL);
3469 ADD_TREE (t1, cli_addr);
3479 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3480 t1->data.i = ARG_POS (n);
3481 if (!MONO_TYPE_ISSTRUCT (ARG_TYPE (n)))
3482 t1 = ctree_create_load (cfg, ARG_TYPE (n), t1, &svt, TRUE);
3483 PUSH_TREE (t1, svt);
3492 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3493 t1->data.i = ARG_POS (n);
3494 PUSH_TREE (t1, svt);
3501 token = read32 (ip);
3504 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
3505 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
3506 MonoType *type = mono_type_create_from_typespec (image, token);
3507 t1->data.i = mono_type_size (type, &align);
3508 mono_metadata_free_type (type);
3510 MonoClass *szclass = mono_class_get (image, token);
3511 mono_class_init (szclass);
3512 g_assert (szclass->valuetype);
3513 t1->data.i = mono_class_value_size (szclass, &align);
3516 PUSH_TREE (t1, VAL_I32);
3523 t1 = mono_ctree_new (mp, MB_TERM_CPSRC, sp [1], sp [2]);
3524 t1 = mono_ctree_new (mp, MB_TERM_CPBLK, sp [0], t1);
3525 ADD_TREE (t1, cli_addr);
3528 case CEE_UNALIGNED_: {
3530 /* fixme: implement me */
3533 case CEE_VOLATILE_: {
3535 /* fixme: implement me */
3540 tail_recursion = TRUE;
3542 case CEE_LOCALLOC: {
3546 t1 = mono_ctree_new (mp, MB_TERM_LOCALLOC, *sp, NULL);
3547 t1->data.i = header->init_locals;
3548 PUSH_TREE (t1, VAL_POINTER);
3555 t1 = mono_ctree_new (mp, MB_TERM_CPSRC, sp [1], sp [2]);
3556 t1 = mono_ctree_new (mp, MB_TERM_INITBLK, sp [0], t1);
3557 ADD_TREE (t1, cli_addr);
3561 g_error ("Unimplemented opcode at IL_%04x "
3562 "0xFE %02x", ip - header->code, *ip);
3567 g_warning ("unknown instruction `%s' at IL_%04X",
3568 mono_opcode_names [*ip], ip - header->code);
3569 if (mono_debug_format == MONO_DEBUG_FORMAT_NONE) {
3572 mono_print_forest (cfg, forest);
3573 g_assert_not_reached ();
3577 if ((depth = sp - stack)) {
3578 //printf ("DEPTH %d %d\n", depth, sp [0]->op);
3579 //mono_print_forest (cfg, forest);
3580 create_outstack (cfg, bb, stack, sp - stack);
3584 superblock_end = TRUE;
3587 superblock_end = TRUE;
3588 //printf ("unreached block %d\n", i);
3590 if (repeat_count >= 10) {
3591 /*mono_print_forest (cfg, forest);
3592 g_warning ("repeat count exceeded at ip: 0x%04x in %s\n", bb->cli_addr, cfg->method->name);*/
3596 //printf ("BBE %d %d %d %d\n", i, bb->reached, bb->finished, superblock_end);
3600 //printf ("REPEAT %d\n", repeat);
3601 mono_jit_stats.analyze_stack_repeat++;
3610 mono_cfg_free (MonoFlowGraph *cfg)
3614 for (i = 0; i < cfg->block_count; i++) {
3615 if (!cfg->bblocks [i].reached)
3617 g_ptr_array_free (cfg->bblocks [i].forest, TRUE);
3618 g_list_free (cfg->bblocks [i].succ);
3622 g_free (cfg->bcinfo);
3625 g_free (cfg->bblocks);
3627 g_array_free (cfg->varinfo, TRUE);
3629 mono_mempool_destroy (cfg->mp);
3632 int mono_exc_esp_offset = 0;
3634 static MonoFlowGraph *
3635 mono_cfg_new (MonoMethod *method)
3639 MonoMemPool *mp = mono_mempool_new ();
3641 g_assert (((MonoMethodNormal *)method)->header);
3643 cfg = mono_mempool_alloc0 (mp, sizeof (MonoFlowGraph));
3645 cfg->domain = mono_domain_get ();
3646 cfg->method = method;
3649 /* reserve space to save LMF */
3650 cfg->locals_size = sizeof (MonoLMF);
3652 mono_exc_esp_offset = - cfg->locals_size;
3654 /* aligment check */
3655 g_assert (!(cfg->locals_size & 0x7));
3657 /* fixme: we should also consider loader optimisation attributes */
3658 cfg->share_code = mono_jit_share_code;
3660 cfg->varinfo = g_array_new (FALSE, TRUE, sizeof (MonoVarInfo));
3662 SET_VARINFO (vi, 0, 0, 0, 0);
3663 g_array_append_val (cfg->varinfo, vi); /* add invalid value at position 0 */
3665 cfg->intvars = mono_mempool_alloc0 (mp, sizeof (guint16) * VAL_DOUBLE *
3666 ((MonoMethodNormal *)method)->header->max_stack);
3668 mono_analyze_flow (cfg);
3670 if (!mono_analyze_stack (cfg)) {
3671 mono_cfg_free (cfg);
3679 mono_get_runtime_method (MonoMethod* method)
3682 const char *name = method->name;
3684 if (method->klass->parent == mono_defaults.multicastdelegate_class) {
3685 if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
3686 return (gpointer)mono_delegate_ctor;
3687 } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
3688 nm = mono_marshal_get_delegate_invoke (method);
3689 return mono_compile_method (nm);
3690 } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
3691 nm = mono_marshal_get_delegate_begin_invoke (method);
3692 return mono_compile_method (nm);
3693 } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
3694 nm = mono_marshal_get_delegate_end_invoke (method);
3695 return mono_compile_method (nm);
3701 #ifdef MONO_USE_EXC_TABLES
3703 mono_type_blittable (MonoType *type)
3708 switch (type->type){
3709 case MONO_TYPE_VOID:
3723 case MONO_TYPE_VALUETYPE:
3724 case MONO_TYPE_CLASS:
3725 return type->data.klass->blittable;
3735 mono_method_blittable (MonoMethod *method)
3737 MonoMethodSignature *sig;
3743 if (!mono_has_unwind_info (method)) {
3747 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
3750 sig = method->signature;
3752 if (!mono_type_blittable (sig->ret))
3755 for (i = 0; i < sig->param_count; i++)
3756 if (!mono_type_blittable (sig->params [i]))
3764 * mono_compile_method:
3765 * @method: pointer to the method info
3767 * JIT compilation of a single method.
3769 * Returns: a pointer to the newly created code.
3772 mono_jit_compile_method (MonoMethod *method)
3774 MonoDomain *target_domain, *domain = mono_domain_get ();
3777 GHashTable *jit_code_hash;
3779 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
3780 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
3782 if (!method->info) {
3785 if (!method->addr && (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
3786 mono_lookup_pinvoke_call (method);
3787 #ifdef MONO_USE_EXC_TABLES
3788 if (mono_method_blittable (method)) {
3789 method->info = method->addr;
3792 nm = mono_marshal_get_native_wrapper (method);
3793 method->info = mono_compile_method (nm);
3794 #ifdef MONO_USE_EXC_TABLES
3798 return method->info;
3801 if (mono_jit_share_code)
3802 target_domain = mono_root_domain;
3804 target_domain = domain;
3806 jit_code_hash = target_domain->jit_code_hash;
3808 if ((addr = g_hash_table_lookup (jit_code_hash, method))) {
3809 mono_jit_stats.methods_lookups++;
3814 mono_jit_stats.methods_compiled++;
3816 if (mono_jit_trace_calls || mono_jit_dump_asm || mono_jit_dump_forest) {
3817 printf ("Start JIT compilation of %s, domain '%s'\n",
3818 mono_method_full_name (method, TRUE), target_domain->friendly_name);
3821 if (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
3822 if (!(addr = mono_get_runtime_method (method))) {
3823 mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
3824 if (mono_debug_format != MONO_DEBUG_FORMAT_NONE)
3827 g_error ("Don't know how to exec runtime method %s", mono_method_full_name (method, TRUE));
3830 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
3832 gulong code_size_ratio;
3834 mono_profiler_method_jit (method);
3836 if (!(cfg = mono_cfg_new (method))) {
3837 mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
3841 cfg->code_size = MAX (header->code_size * 5, 256);
3842 cfg->start = cfg->code = g_malloc (cfg->code_size);
3844 if (mono_method_has_breakpoint (method, FALSE) || mono_debug_insert_breakpoint)
3845 x86_breakpoint (cfg->code);
3846 else if (mono_debug_format != MONO_DEBUG_FORMAT_NONE)
3847 x86_nop (cfg->code);
3849 if (mono_debug_insert_breakpoint > 0)
3850 mono_debug_insert_breakpoint--;
3852 if (!(ji = arch_jit_compile_cfg (target_domain, cfg))) {
3853 mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
3859 mono_jit_stats.allocated_code_size += cfg->code_size;
3861 code_size_ratio = cfg->code - cfg->start;
3862 if (code_size_ratio > mono_jit_stats.biggest_method_size) {
3863 mono_jit_stats.biggest_method_size = code_size_ratio;
3864 mono_jit_stats.biggest_method = method;
3866 code_size_ratio = (code_size_ratio * 100) / header->code_size;
3867 if (code_size_ratio > mono_jit_stats.max_code_size_ratio) {
3868 mono_jit_stats.max_code_size_ratio = code_size_ratio;
3869 mono_jit_stats.max_ratio_method = method;
3873 if (mono_jit_dump_asm) {
3874 char *id = g_strdup_printf ("%s.%s_%s", method->klass->name_space,
3875 method->klass->name, method->name);
3876 mono_disassemble_code (cfg->start, cfg->code - cfg->start, id);
3879 if (mono_debug_format != MONO_DEBUG_FORMAT_NONE)
3880 mono_debug_add_method (cfg);
3883 mono_jit_stats.native_code_size += ji->code_size;
3885 if (header->num_clauses) {
3886 int i, start_block, end_block, filter_block;
3888 ji->num_clauses = header->num_clauses;
3889 ji->clauses = mono_mempool_alloc0 (target_domain->mp,
3890 sizeof (MonoJitExceptionInfo) * header->num_clauses);
3892 for (i = 0; i < header->num_clauses; i++) {
3893 MonoExceptionClause *ec = &header->clauses [i];
3894 MonoJitExceptionInfo *ei = &ji->clauses [i];
3896 ei->flags = ec->flags;
3898 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
3899 g_assert (cfg->bcinfo [ec->token_or_filter].is_block_start);
3900 filter_block = cfg->bcinfo [ec->token_or_filter].block_id;
3901 ei->data.filter = cfg->start + cfg->bblocks [filter_block].addr;
3903 ei->data.token = ec->token_or_filter;
3906 g_assert (cfg->bcinfo [ec->try_offset].is_block_start);
3907 start_block = cfg->bcinfo [ec->try_offset].block_id;
3908 end_block = cfg->bcinfo [ec->try_offset + ec->try_len].block_id;
3909 g_assert (cfg->bcinfo [ec->try_offset + ec->try_len].is_block_start);
3911 ei->try_start = cfg->start + cfg->bblocks [start_block].addr;
3912 ei->try_end = cfg->start + cfg->bblocks [end_block].addr;
3914 g_assert (cfg->bcinfo [ec->handler_offset].is_block_start);
3915 start_block = cfg->bcinfo [ec->handler_offset].block_id;
3916 ei->handler_start = cfg->start + cfg->bblocks [start_block].addr;
3920 mono_jit_info_table_add (target_domain, ji);
3922 mono_regset_free (cfg->rs);
3924 mono_cfg_free (cfg);
3926 mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
3929 if (mono_jit_trace_calls || mono_jit_dump_asm || mono_jit_dump_forest) {
3930 printf ("END JIT compilation of %s %p %p, domain '%s'\n",
3931 mono_method_full_name (method, FALSE),
3934 target_domain->friendly_name);
3937 g_hash_table_insert (jit_code_hash, method, addr);
3942 /* mono_jit_create_remoting_trampoline:
3943 * @method: pointer to the method info
3945 * Creates a trampoline which calls the remoting functions. This
3946 * is used in the vtable of transparent proxies.
3948 * Returns: a pointer to the newly created code
3951 mono_jit_create_remoting_trampoline (MonoMethod *method)
3954 guint8 *addr = NULL;
3956 nm = mono_marshal_get_remoting_invoke (method);
3957 addr = mono_compile_method (nm);
3962 /* this function is never called */
3964 ves_array_set (MonoArray *this, ...)
3966 g_assert_not_reached ();
3969 /* this function is never called */
3971 ves_array_get (MonoArray *this, ...)
3973 g_assert_not_reached ();
3978 * @assembly: reference to an assembly
3979 * @argc: argument count
3980 * @argv: argument vector
3982 * Start execution of a program.
3985 mono_jit_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
3987 MonoImage *image = assembly->image;
3990 method = mono_get_method (image, mono_image_get_entry_point (image), NULL);
3992 return mono_runtime_run_main (method, argc, argv, NULL);
3995 #ifdef PLATFORM_WIN32
3996 #define GET_CONTEXT \
3997 struct sigcontext *ctx = (struct sigcontext*)_dummy;
3999 #define GET_CONTEXT \
4000 void **_p = (void **)&_dummy; \
4001 struct sigcontext *ctx = (struct sigcontext *)++_p;
4005 sigfpe_signal_handler (int _dummy)
4010 exc = mono_get_exception_divide_by_zero ();
4012 arch_handle_exception (ctx, exc, FALSE);
4016 sigill_signal_handler (int _dummy)
4020 exc = mono_get_exception_execution_engine ("SIGILL");
4022 arch_handle_exception (ctx, exc, FALSE);
4026 sigsegv_signal_handler (int _dummy)
4031 exc = mono_get_exception_null_reference ();
4033 arch_handle_exception (ctx, exc, FALSE);
4037 sigusr1_signal_handler (int _dummy)
4042 thread = mono_thread_current ();
4044 g_assert (thread->abort_exc);
4046 arch_handle_exception (ctx, thread->abort_exc, FALSE);
4050 mono_get_lmf_addr (void)
4052 MonoJitTlsData *jit_tls;
4054 if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
4055 return &jit_tls->lmf;
4057 g_assert_not_reached ();
4062 * mono_thread_abort:
4063 * @obj: exception object
4065 * abort the thread, print exception information and stack trace
4068 mono_thread_abort (MonoObject *obj)
4070 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
4078 mono_thread_start_cb (gpointer stack_start)
4080 MonoJitTlsData *jit_tls;
4082 jit_tls = g_new0 (MonoJitTlsData, 1);
4084 TlsSetValue (mono_jit_tls_id, jit_tls);
4086 jit_tls->abort_func = mono_thread_abort;
4087 jit_tls->end_of_stack = stack_start;
4090 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
4093 mono_thread_abort_dummy (MonoObject *obj)
4095 if (mono_thread_attach_aborted_cb)
4096 mono_thread_attach_aborted_cb (obj);
4098 mono_thread_abort (obj);
4102 mono_thread_attach_cb (gpointer stack_start)
4104 MonoJitTlsData *jit_tls;
4106 jit_tls = g_new0 (MonoJitTlsData, 1);
4108 TlsSetValue (mono_jit_tls_id, jit_tls);
4110 jit_tls->abort_func = mono_thread_abort_dummy;
4111 jit_tls->end_of_stack = stack_start;
4114 static CRITICAL_SECTION ms;
4117 mono_runtime_install_handlers (void)
4119 #ifndef PLATFORM_WIN32
4120 struct sigaction sa;
4123 #ifdef PLATFORM_WIN32
4125 win32_seh_set_handler(SIGFPE, sigfpe_signal_handler);
4126 win32_seh_set_handler(SIGILL, sigill_signal_handler);
4127 win32_seh_set_handler(SIGSEGV, sigsegv_signal_handler);
4128 #else /* !PLATFORM_WIN32 */
4130 /* libpthreads has its own implementation of sigaction(),
4131 * but it seems to work well with our current exception
4132 * handlers. If not we must call syscall directly instead
4136 sa.sa_handler = sigfpe_signal_handler;
4137 sigemptyset (&sa.sa_mask);
4139 //g_assert (syscall (SYS_sigaction, SIGFPE, &sa, NULL) != -1);
4140 g_assert (sigaction (SIGFPE, &sa, NULL) != -1);
4143 sa.sa_handler = sigill_signal_handler;
4144 sigemptyset (&sa.sa_mask);
4146 //g_assert (syscall (SYS_sigaction, SIGILL, &sa, NULL) != -1);
4147 g_assert (sigaction (SIGILL, &sa, NULL) != -1);
4149 /* catch the thread abort signal */
4150 sa.sa_handler = sigusr1_signal_handler;
4151 sigemptyset (&sa.sa_mask);
4153 //g_assert (syscall (SYS_sigaction, SIGILL, &sa, NULL) != -1);
4154 g_assert (sigaction (mono_thread_get_abort_signal (), &sa, NULL) != -1);
4158 sa.sa_handler = sigsegv_signal_handler;
4159 sigemptyset (&sa.sa_mask);
4161 //g_assert (syscall (SYS_sigaction, SIGSEGV, &sa, NULL) != -1);
4162 g_assert (sigaction (SIGSEGV, &sa, NULL) != -1);
4164 #endif /* PLATFORM_WIN32 */
4168 mono_jit_init (const char *file) {
4173 mono_runtime_install_handlers ();
4176 mono_add_internal_call ("System.Array::Set", ves_array_set);
4177 mono_add_internal_call ("System.Array::Get", ves_array_get);
4178 mono_add_internal_call ("System.Array::Address", ves_array_element_address);
4179 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
4180 ves_icall_get_frame_info);
4181 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",
4182 ves_icall_get_trace);
4183 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers", mono_runtime_install_handlers);
4185 metadata_section = &ms;
4186 InitializeCriticalSection (metadata_section);
4188 mono_jit_tls_id = TlsAlloc ();
4189 mono_thread_start_cb ((gpointer)-1);
4191 mono_install_compile_method (mono_jit_compile_method);
4192 mono_install_trampoline (arch_create_jit_trampoline);
4193 mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline);
4194 mono_install_handler (arch_get_throw_exception ());
4195 mono_install_runtime_invoke (mono_jit_runtime_invoke);
4196 mono_install_stack_walk (mono_jit_walk_stack);
4197 mono_install_get_config_dir ();
4199 domain = mono_init (file);
4200 mono_runtime_init (domain, mono_thread_start_cb,
4201 mono_thread_attach_cb);
4207 mono_jit_cleanup (MonoDomain *domain)
4211 * mono_runtime_cleanup() needs to be called early since
4212 * it needs the execution engine still fully working (it will
4213 * wait for other threads to finish).
4215 mono_runtime_cleanup (domain);
4217 mono_domain_finalize (domain);
4219 mono_debug_cleanup ();
4221 #ifdef PLATFORM_WIN32
4222 win32_seh_cleanup();
4225 mono_domain_unload (domain, TRUE);
4227 if (mono_jit_stats.enabled) {
4228 g_print ("Mono Jit statistics\n");
4229 g_print ("Compiled methods: %ld\n", mono_jit_stats.methods_compiled);
4230 g_print ("Methods cache lookup: %ld\n", mono_jit_stats.methods_lookups);
4231 g_print ("Method trampolines: %ld\n", mono_jit_stats.method_trampolines);
4232 g_print ("Basic blocks: %ld\n", mono_jit_stats.basic_blocks);
4233 g_print ("Max basic blocks: %ld\n", mono_jit_stats.max_basic_blocks);
4234 g_print ("Allocated vars: %ld\n", mono_jit_stats.allocate_var);
4235 g_print ("Analyze stack repeat: %ld\n", mono_jit_stats.analyze_stack_repeat);
4236 g_print ("Compiled CIL code size: %ld\n", mono_jit_stats.cil_code_size);
4237 g_print ("Native code size: %ld\n", mono_jit_stats.native_code_size);
4238 g_print ("Max code size ratio: %.2f (%s::%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
4239 mono_jit_stats.max_ratio_method->klass->name, mono_jit_stats.max_ratio_method->name);
4240 g_print ("Biggest method: %ld (%s::%s)\n", mono_jit_stats.biggest_method_size,
4241 mono_jit_stats.biggest_method->klass->name, mono_jit_stats.biggest_method->name);
4242 g_print ("Code reallocs: %ld\n", mono_jit_stats.code_reallocs);
4243 g_print ("Allocated code size: %ld\n", mono_jit_stats.allocated_code_size);
4244 g_print ("Inlineable methods: %ld\n", mono_jit_stats.inlineable_methods);
4245 g_print ("Inlined methods: %ld\n", mono_jit_stats.inlined_methods);
4247 g_print ("\nCreated object count: %ld\n", mono_stats.new_object_count);
4248 g_print ("Initialized classes: %ld\n", mono_stats.initialized_class_count);
4249 g_print ("Used classes: %ld\n", mono_stats.used_class_count);
4250 g_print ("Static data size: %ld\n", mono_stats.class_static_data_size);
4251 g_print ("VTable data size: %ld\n", mono_stats.class_vtable_size);
4254 DeleteCriticalSection (metadata_section);
4260 * @image: reference to an image
4261 * @verbose: If true, print debugging information on stdout.
4263 * JIT compilation of all methods in the image.
4266 mono_jit_compile_image (MonoImage *image, int verbose)
4269 MonoTableInfo *t = &image->tables [MONO_TABLE_METHOD];
4272 for (i = 0; i < t->rows; i++) {
4274 method = mono_get_method (image,
4275 (MONO_TABLE_METHOD << 24) | (i + 1),
4279 g_print ("Compiling: %s:%s\n\n", image->assembly_name, method->name);
4281 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT) {
4283 printf ("ABSTARCT\n");
4285 mono_compile_method (method);