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 MonoJitStats mono_jit_stats;
234 CRITICAL_SECTION *metadata_section = NULL;
237 * We sometimes need static data, for example the forest generator need it to
238 * store constants or class data.
240 inline static gpointer
241 mono_alloc_static (int size)
243 return g_malloc (size);
245 inline static gpointer
246 mono_alloc_static0 (int size)
248 return g_malloc0 (size);
251 typedef void (*MonoCCtor) (void);
254 mono_allocate_intvar (MonoFlowGraph *cfg, int slot, MonoValueType type)
256 int size, align, vnum, pos;
258 g_assert (type != VAL_UNKNOWN);
260 /* take care if you modify MonoValueType */
261 g_assert (VAL_DOUBLE == 4);
263 /* fixme: machine dependant */
264 if (type == VAL_POINTER)
265 type = VAL_I32; /* VAL_I32 and VAL_POINTER share the same slot */
267 pos = type - 1 + slot * VAL_DOUBLE;
269 if ((vnum = cfg->intvars [pos]))
271 mono_get_val_sizes (type, &size, &align);
273 cfg->intvars[pos] = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, type);
275 return cfg->intvars[pos];
279 mono_allocate_excvar (MonoFlowGraph *cfg)
284 cfg->excvar = arch_allocate_var (cfg, 4, 4, MONO_TEMPVAR, VAL_POINTER);
286 VARINFO (cfg, cfg->excvar).isvolatile = 1;
292 * mono_jit_runtime_invoke:
293 * @method: the method to invoke
295 * @params: array of parameter values.
296 * @exc: used to catch exceptions objects
299 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
302 MonoObject *(*runtime_invoke) (MonoObject *this, void **params, MonoObject **exc);
304 invoke = mono_marshal_get_runtime_invoke (method);
305 runtime_invoke = mono_compile_method (invoke);
306 return runtime_invoke (obj, params, exc);
311 * @cfg: pointer to the control flow graph
312 * @type: the type of the value to load
313 * @addr: the address of the value
315 * Creates a tree to load the value at address @addr.
317 inline static MBTree *
318 ctree_create_load (MonoFlowGraph *cfg, MonoType *type, MBTree *addr, MonoValueType *svt, gboolean arg)
320 MonoMemPool *mp = cfg->mp;
325 ldind = mono_map_ldarg_type (type, svt);
327 ldind = mono_map_ldind_type (type, svt);
329 t = mono_ctree_new (mp, ldind, addr, NULL);
335 * ctree_create_store:
336 * @mp: pointer to a memory pool
337 * @s: the value (tree) to store
338 * @type: the type of the value
339 * @addr: the address of the value
341 * Creates a tree to store the value @s at address @addr.
343 inline static MBTree *
344 ctree_create_store (MonoFlowGraph *cfg, MonoType *type, MBTree *addr,
345 MBTree *s, gboolean arg)
347 MonoMemPool *mp = cfg->mp;
352 stind = mono_map_starg_type (type);
354 stind = mono_map_stind_type (type);
356 t = mono_ctree_new (mp, stind, addr, s);
358 if (MONO_TYPE_ISSTRUCT (type))
359 t->data.i = mono_class_value_size (type->data.klass, NULL);
364 inline static MBTree *
365 ctree_dup_address (MonoMemPool *mp, MBTree *s)
373 t = mono_ctree_new_leaf (mp, s->op);
374 t->data.i = s->data.i;
375 t->svt = VAL_POINTER;
378 g_warning ("unknown tree opcode %d", s->op);
379 g_assert_not_reached ();
386 * Create a duplicate of the value of a tree. This is
387 * easy for trees starting with LDIND/STIND, since the
388 * duplicate is simple a LDIND tree with the same address.
389 * For other trees we have to split the tree into one tree
390 * storing the value to a new temporary variable, and
391 * another tree which loads that value back. We can then
392 * duplicate the second tree.
395 ctree_create_dup (MonoMemPool *mp, MBTree *s)
400 case MB_TERM_STIND_I1:
401 case MB_TERM_LDIND_I1:
402 t = ctree_dup_address (mp, s->left);
403 t = mono_ctree_new (mp, MB_TERM_LDIND_I1, t, NULL);
406 case MB_TERM_STIND_I2:
407 case MB_TERM_LDIND_I2:
408 t = ctree_dup_address (mp, s->left);
409 t = mono_ctree_new (mp, MB_TERM_LDIND_I2, t, NULL);
412 case MB_TERM_STIND_I4:
413 case MB_TERM_LDIND_I4:
414 t = ctree_dup_address (mp, s->left);
415 t = mono_ctree_new (mp, MB_TERM_LDIND_I4, t, NULL);
418 case MB_TERM_STIND_I8:
419 case MB_TERM_LDIND_I8:
420 t = ctree_dup_address (mp, s->left);
421 t = mono_ctree_new (mp, MB_TERM_LDIND_I8, t, NULL);
424 case MB_TERM_STIND_R4:
425 case MB_TERM_LDIND_R4:
426 t = ctree_dup_address (mp, s->left);
427 t = mono_ctree_new (mp, MB_TERM_LDIND_R4, t, NULL);
430 case MB_TERM_STIND_R8:
431 case MB_TERM_LDIND_R8:
432 t = ctree_dup_address (mp, s->left);
433 t = mono_ctree_new (mp, MB_TERM_LDIND_R8, t, NULL);
436 case MB_TERM_STIND_OBJ:
437 case MB_TERM_LDIND_OBJ:
438 t = ctree_dup_address (mp, s->left);
439 t = mono_ctree_new (mp, MB_TERM_LDIND_OBJ, t, NULL);
440 t->svt = VAL_UNKNOWN;
443 g_warning ("unknown op \"%s\"", mono_burg_term_string [s->op]);
444 g_assert_not_reached ();
451 mono_store_tree (MonoFlowGraph *cfg, int slot, MBTree *s, MBTree **tdup)
453 MonoMemPool *mp = cfg->mp;
458 case MB_TERM_STIND_I1:
459 case MB_TERM_LDIND_I1:
460 case MB_TERM_STIND_I2:
461 case MB_TERM_LDIND_I2:
462 case MB_TERM_STIND_I4:
463 case MB_TERM_LDIND_I4:
464 case MB_TERM_STIND_I8:
465 case MB_TERM_LDIND_I8:
466 case MB_TERM_STIND_R4:
467 case MB_TERM_LDIND_R4:
468 case MB_TERM_STIND_R8:
469 case MB_TERM_LDIND_R8: {
471 vnum = mono_allocate_intvar (cfg, slot, s->svt);
473 if (s->left->op == MB_TERM_ADDR_L && s->left->data.i == vnum) {
475 *tdup = ctree_create_dup (mp, s);
481 *tdup = ctree_create_dup (mp, s);
486 g_assert (s->svt != VAL_UNKNOWN);
490 vnum = mono_allocate_intvar (cfg, slot, s->svt);
493 mono_get_val_sizes (s->svt, &size, &align);
494 vnum = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, s->svt);
497 t = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
500 t = mono_ctree_new (mp, mono_map_store_svt_type (s->svt), t, s);
506 *tdup = ctree_create_dup (mp, t);
512 mono_find_final_block (MonoFlowGraph *cfg, guint32 ip, guint32 target, int type)
514 MonoMethod *method = cfg->method;
515 MonoBytecodeInfo *bcinfo = cfg->bcinfo;
516 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
517 MonoExceptionClause *clause;
520 for (i = 0; i < header->num_clauses; ++i) {
521 clause = &header->clauses [i];
523 if (MONO_OFFSET_IN_CLAUSE (clause, ip) &&
524 (!MONO_OFFSET_IN_CLAUSE (clause, target))) {
525 if (clause->flags & type) {
526 g_assert (bcinfo [clause->handler_offset].is_block_start);
527 return &cfg->bblocks [bcinfo [clause->handler_offset].block_id];
535 mono_cfg_add_successor (MonoFlowGraph *cfg, MonoBBlock *bb, gint32 target)
540 g_assert (cfg->bcinfo [target].is_block_start);
542 tbb = &cfg->bblocks [cfg->bcinfo [target].block_id];
545 for (l = bb->succ; l; l = l->next) {
546 MonoBBlock *t = (MonoBBlock *)l->data;
551 bb->succ = g_list_prepend (bb->succ, tbb);
555 #define CREATE_BLOCK(t) {if (!bcinfo [t].is_block_start) {block_count++;bcinfo [t].is_block_start = 1; }}
558 mono_analyze_flow (MonoFlowGraph *cfg)
560 MonoMethod *method = cfg->method;
561 const unsigned char *ip, *end;
562 MonoMethodHeader *header;
563 MonoBytecodeInfo *bcinfo;
564 MonoExceptionClause *clause;
565 MonoBBlock *bblocks, *bb;
566 const MonoOpcode *opcode;
570 header = ((MonoMethodNormal *)method)->header;
572 bcinfo = g_malloc0 (header->code_size * sizeof (MonoBytecodeInfo));
573 bcinfo [0].is_block_start = 1;
578 end = ip + header->code_size;
580 mono_jit_stats.cil_code_size += header->code_size;
582 for (i = 0; i < header->num_clauses; ++i) {
583 clause = &header->clauses [i];
585 CREATE_BLOCK (clause->try_offset);
586 CREATE_BLOCK (clause->handler_offset);
588 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER)
589 CREATE_BLOCK (clause->token_or_filter);
593 guint32 cli_addr = ip - header->code;
595 //printf ("IL%04x OPCODE %s\n", cli_addr, mono_opcode_names [*ip]);
598 CREATE_BLOCK (cli_addr);
602 i = mono_opcode_value (&ip);
604 opcode = &mono_opcodes [i];
606 switch (opcode->flow_type) {
607 case MONO_FLOW_RETURN:
608 case MONO_FLOW_ERROR:
611 case MONO_FLOW_BRANCH: /* we handle branch when checking the argument type */
612 case MONO_FLOW_COND_BRANCH:
618 g_assert_not_reached ();
621 switch (opcode->argument) {
625 case MonoInlineString:
626 mono_ldstr (mono_domain_get (), method->klass->image, mono_metadata_token_index (read32 (ip + 1)));
629 case MonoInlineField:
630 case MonoInlineMethod:
633 case MonoShortInlineR:
640 case MonoShortInlineVar:
641 case MonoShortInlineI:
644 case MonoShortInlineBrTarget:
646 i = (signed char)*ip;
648 CREATE_BLOCK (cli_addr + 2 + i);
652 case MonoInlineBrTarget:
656 CREATE_BLOCK (cli_addr + 5 + i);
659 case MonoInlineSwitch: {
660 gint32 st, target, n;
664 st = cli_addr + 5 + 4 * n;
667 for (i = 0; i < n; i++) {
668 target = read32 (ip) + st;
670 CREATE_BLOCK (target);
673 * Note: the code didn't set block_end in switch.
682 g_assert_not_reached ();
687 g_assert (block_count);
689 bb = bblocks = g_malloc0 (sizeof (MonoBBlock) * block_count);
692 bblocks [0].reached = 1;
694 for (i = 0; i < header->code_size; i++) {
695 if (bcinfo [i].is_block_start) {
697 bb->num = block_count;
698 bb->forest = g_ptr_array_new ();
700 bb [-1].length = i - bb [-1].cli_addr;
701 bcinfo [i].block_id = block_count;
706 bb [-1].length = header->code_size - bb [-1].cli_addr;
708 cfg->bcinfo = bcinfo;
709 cfg->bblocks = bblocks;
710 cfg->block_count = block_count;
712 mono_jit_stats.basic_blocks += block_count;
713 mono_jit_stats.max_basic_blocks = MAX (block_count, mono_jit_stats.max_basic_blocks);
715 for (i = 0; i < header->num_clauses; ++i) {
716 MonoBBlock *sbb, *tbb;
717 clause = &header->clauses [i];
718 sbb = &cfg->bblocks [bcinfo [clause->try_offset].block_id];
719 tbb = &cfg->bblocks [bcinfo [clause->handler_offset].block_id];
720 g_assert (sbb && tbb);
721 sbb->succ = g_list_prepend (sbb->succ, tbb);
725 end = ip + header->code_size;
729 guint32 cli_addr = ip - header->code;
731 if (bcinfo [cli_addr].is_block_start) {
732 MonoBBlock *tbb = &cfg->bblocks [bcinfo [cli_addr].block_id];
734 bb->succ = g_list_prepend (bb->succ, tbb);
739 i = mono_opcode_value (&ip);
741 opcode = &mono_opcodes [i];
743 switch (opcode->argument) {
747 case MonoInlineString:
749 case MonoInlineField:
750 case MonoInlineMethod:
753 case MonoShortInlineR:
760 case MonoShortInlineVar:
761 case MonoShortInlineI:
764 case MonoShortInlineBrTarget:
766 i = (signed char)*ip;
768 mono_cfg_add_successor (cfg, bb, cli_addr + 2 + i);
769 if (opcode->flow_type == MONO_FLOW_COND_BRANCH)
770 mono_cfg_add_successor (cfg, bb, cli_addr + 2);
772 case MonoInlineBrTarget:
776 mono_cfg_add_successor (cfg, bb, cli_addr + 5 + i);
777 if (opcode->flow_type == MONO_FLOW_COND_BRANCH)
778 mono_cfg_add_successor (cfg, bb, cli_addr + 5);
780 case MonoInlineSwitch: {
781 gint32 st, target, n;
785 st = cli_addr + 5 + 4 * n;
786 mono_cfg_add_successor (cfg, bb, st);
788 for (i = 0; i < n; i++) {
789 target = read32 (ip) + st;
791 mono_cfg_add_successor (cfg, bb, target);
800 g_assert_not_reached ();
806 * ves_array_element_address:
807 * @this: a pointer to the array object
809 * Returns: the address of an array element.
812 ves_array_element_address (MonoArray *this, ...)
821 g_assert (this != NULL);
825 class = this->obj.vtable->klass;
827 ind = va_arg(ap, int);
828 g_assert (this->bounds != NULL);
830 ind -= this->bounds [0].lower_bound;
831 for (i = 1; i < class->rank; i++) {
832 ind = ind*this->bounds [i].length + va_arg(ap, int) -
833 this->bounds [i].lower_bound;;
836 if (ind >= this->max_length)
837 mono_raise_exception (mono_get_exception_index_out_of_range ());
839 esize = mono_array_element_size (class);
840 ea = (gpointer*)((char*)this->vector + (ind * esize));
841 //printf ("AADDRESS %p %p %d %d %08X\n", this, ea, ind, esize, *(gpointer *)ea);
849 mono_array_new_va (MonoMethod *cm, ...)
851 MonoDomain *domain = mono_domain_get ();
854 guint32 *lower_bounds;
855 int pcount = cm->signature->param_count;
856 int rank = cm->klass->rank;
861 lengths = alloca (sizeof (guint32) * pcount);
862 for (i = 0; i < pcount; ++i)
863 lengths [i] = d = va_arg(ap, int);
865 if (rank == pcount) {
866 /* Only lengths provided. */
869 g_assert (pcount == (rank * 2));
870 /* lower bounds are first. */
871 lower_bounds = lengths;
876 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
879 #define ADD_TREE(t,a) do { t->cli_addr = a; g_ptr_array_add (forest, (t)); } while (0)
880 #define PUSH_TREE(t,k) do { int tt = k; *sp = t; t->svt = tt; t->cli_addr = cli_addr; sp++; } while (0)
882 #define LOCAL_POS(n) (1 + n)
885 #define LOCAL_TYPE(n) ((header)->locals [(n)]->type == MONO_TYPE_BOOLEAN && !(header)->locals [(n)]->byref ? &mono_defaults.int32_class->byval_arg : (header)->locals [(n)])
887 #define LOCAL_TYPE(n) ((header)->locals [(n)])
890 #define ARG_POS(n) (firstarg + n)
891 #define ARG_TYPE(n) ((n) ? (signature)->params [(n) - (signature)->hasthis] : \
892 (signature)->hasthis ? &method->klass->this_arg: (signature)->params [(0)])
896 * replaces all occurences of variable @varnum in @tree with @copy.
899 mono_copy_used_var (MonoFlowGraph *cfg, MBTree *tree, int varnum, MBTree **copy)
905 mono_copy_used_var (cfg, tree->left, varnum, copy);
907 mono_copy_used_var (cfg, tree->right, varnum, copy);
910 case MB_TERM_LDIND_I1:
911 case MB_TERM_LDIND_I2:
912 case MB_TERM_LDIND_I4:
913 case MB_TERM_LDIND_I8:
914 case MB_TERM_LDIND_R4:
915 case MB_TERM_LDIND_R8:
916 if (tree->left->op == MB_TERM_ADDR_L &&
917 tree->left->data.i == varnum) {
919 tree->left->data.i = (*copy)->left->data.i;
923 mono_get_val_sizes (tree->svt, &size, &align);
924 v = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, tree->svt);
926 t1 = mono_ctree_new_leaf (cfg->mp, MB_TERM_ADDR_L);
929 t2 = mono_ctree_new_leaf (cfg->mp, MB_TERM_ADDR_L);
931 t2 = mono_ctree_new (cfg->mp, tree->op, t2, NULL);
933 t2 = mono_ctree_new (cfg->mp, mono_map_store_svt_type (tree->svt), t1, t2);
936 tree->left->data.i = v;
944 * if a variable is modified and there are still referencence
945 * to it on the runtime stack we need to store the value into
946 * a temporary variable and use that value instead of the
950 mono_stack_duplicate_used_var (MonoFlowGraph *cfg, MBTree **stack, MBTree **sp, int varnum)
955 mono_copy_used_var (cfg, *stack, varnum, &res);
963 check_inlining (MonoMethod *method)
965 MonoMethodHeader *header;
966 MonoMethodSignature *signature = method->signature;
967 register const unsigned char *ip, *end;
969 int i, arg_used [256];
973 if (method->inline_info)
974 return method->inline_count;
976 method->inline_info = 1;
978 if (method->wrapper_type != MONO_WRAPPER_NONE)
981 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
982 (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
983 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
984 (method->klass->marshalbyref) ||
985 MONO_TYPE_ISSTRUCT (signature->ret))
988 if (!(header = ((MonoMethodNormal *)method)->header) ||
992 if (header->num_clauses)
996 end = ip + header->code_size;
998 for (i = 0; i < 256; i++)
1002 while (!stop && ip < end) {
1051 case CEE_CONV_OVF_I1_UN:
1052 case CEE_CONV_OVF_I2_UN:
1053 case CEE_CONV_OVF_I4_UN:
1054 case CEE_CONV_OVF_I8_UN:
1055 case CEE_CONV_OVF_U1_UN:
1056 case CEE_CONV_OVF_U2_UN:
1057 case CEE_CONV_OVF_U4_UN:
1058 case CEE_CONV_OVF_U8_UN:
1059 case CEE_CONV_OVF_I_UN:
1060 case CEE_CONV_OVF_U_UN:
1072 case CEE_LDELEM_REF:
1080 case CEE_STELEM_REF:
1081 case CEE_CONV_OVF_I1:
1082 case CEE_CONV_OVF_U1:
1083 case CEE_CONV_OVF_I2:
1084 case CEE_CONV_OVF_U2:
1085 case CEE_CONV_OVF_I4:
1086 case CEE_CONV_OVF_U4:
1087 case CEE_CONV_OVF_I8:
1088 case CEE_CONV_OVF_U8:
1093 case CEE_CONV_OVF_I:
1094 case CEE_CONV_OVF_U:
1096 case CEE_ADD_OVF_UN:
1098 case CEE_MUL_OVF_UN:
1100 case CEE_SUB_OVF_UN:
1146 case CEE_CALLVIRT: {
1150 token = read32 (ip);
1153 if (method->wrapper_type != MONO_WRAPPER_NONE)
1154 cm = mono_method_get_wrapper_data (method, token);
1156 cm = mono_get_method (method->klass->image, token, NULL);
1162 /* we do not inline functions containing calls to
1163 stack query functions */
1164 if (cm->klass == mono_defaults.stack_frame_class ||
1165 cm->klass == mono_defaults.stack_trace_class)
1174 int an = (*ip) - CEE_LDARG_0;
1177 arg_used [an] = TRUE;
1185 arg_used [*ip] = TRUE;
1197 if (an > 255 || arg_used [an])
1199 arg_used [an] = TRUE;
1213 case CEE_LDVIRTFTN: {
1217 token = read32 (ip);
1220 cm = mono_get_method (method->klass->image, token, NULL);
1244 !(ip [0] == CEE_RET ||
1246 ip [0] == CEE_STLOC_0 &&
1247 ip [1] == CEE_BR_S &&
1249 ip [3] == CEE_LDLOC_0 &&
1250 ip [4] == CEE_RET)))
1253 if (signature->hasthis && arg_used [0])
1254 method->uses_this = 1;
1256 mono_jit_stats.inlineable_methods++;
1258 return method->inline_count = ip - header->code;
1261 return method->inline_count = -1;
1265 create_outstack (MonoFlowGraph *cfg, MonoBBlock *bb, MBTree **stack, int depth)
1267 MonoMemPool *mp = cfg->mp;
1268 MBTree **c = stack, *t1, *t2;
1269 GPtrArray *forest = bb->forest;
1272 g_assert (bb->reached);
1278 g_assert (bb->outdepth == depth);
1282 bb->outdepth = depth;
1283 bb->outstack = mono_mempool_alloc (mp, depth * sizeof (MBTree *));
1285 for (i = 0; i < depth; i++) {
1286 if ((t1 = mono_store_tree (cfg, i, c [i], &t2)))
1288 bb->outstack [i] = t2;
1293 mark_reached (MonoFlowGraph *cfg, MonoBBlock *target, MBTree **stack, int depth)
1295 MonoMemPool *mp = cfg->mp;
1298 if (target->reached)
1301 target->reached = 1;
1308 if (target->instack) {
1309 g_assert (target->indepth == depth);
1313 target->indepth = depth;
1314 target->instack = mono_mempool_alloc (mp, depth * sizeof (MBTree *));
1316 for (i = 0; i < depth; i++) {
1317 target->instack [i] = ctree_create_dup (mp, stack [i]);
1323 #define MARK_REACHED(bb) do { if (!bb->reached) { bb->reached = 1; }} while (0)
1326 * mono_analyze_stack:
1327 * @cfg: control flow graph
1329 * This is the architecture independent part of JIT compilation.
1330 * It creates a forest of trees which can then be fed into the
1331 * architecture dependent code generation.
1333 * The algorithm is from Andi Krall, the same is used in CACAO
1336 mono_analyze_stack (MonoFlowGraph *cfg)
1338 MonoMethod *method = cfg->method;
1339 MonoMemPool *mp = cfg->mp;
1340 MonoBytecodeInfo *bcinfo = cfg->bcinfo;
1341 MonoMethodHeader *header;
1342 MonoMethodSignature *signature;
1345 MBTree **sp, **stack, **arg_sp, **arg_map = NULL, *t1, *t2, *t3;
1346 MonoJitArgumentInfo *arg_info, default_arg_info [10];
1347 register const unsigned char *ip, *end;
1349 int i, j, depth, repeat_count;
1350 int varnum = 0, firstarg = 0;
1351 gboolean repeat, superblock_end;
1352 MonoBBlock *bb, *tbb;
1354 GList *inline_list = NULL;
1355 gboolean tail_recursion;
1357 header = ((MonoMethodNormal *)method)->header;
1358 signature = method->signature;
1359 image = method->klass->image;
1361 /* we add 10 extra slots for method inlining */
1362 maxstack = header->max_stack + 10;
1363 sp = stack = alloca (sizeof (MBTree *) * (maxstack + 1));
1365 /* allocate local variables */
1367 if (header->num_locals) {
1370 for (i = 0; i < header->num_locals; ++i) {
1372 size = mono_type_size (LOCAL_TYPE (i), &align);
1373 mono_map_ldind_type (header->locals [i], &svt);
1374 varnum = arch_allocate_var (cfg, size, align, MONO_LOCALVAR, svt);
1376 cfg->locals_start_index = varnum;
1380 cfg->args_start_index = firstarg = varnum + 1;
1382 /* allocate argument variables */
1384 if (signature->param_count + 1 < 10)
1385 arg_info = default_arg_info;
1387 arg_info = g_new (MonoJitArgumentInfo, signature->param_count + 1);
1389 arch_get_argument_info (signature, signature->param_count, arg_info);
1391 if (signature->hasthis)
1392 arch_allocate_arg (cfg, &arg_info [0], VAL_POINTER);
1394 if (signature->param_count)
1395 for (i = 0; i < signature->param_count; ++i)
1396 arch_allocate_arg (cfg, &arg_info [i + 1], VAL_UNKNOWN);
1398 if (signature->param_count > 9)
1402 for (i = 0; i < header->num_clauses; ++i) {
1403 MonoExceptionClause *clause = &header->clauses [i];
1404 tbb = &cfg->bblocks [bcinfo [clause->handler_offset].block_id];
1405 if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
1406 clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
1407 tbb->instack = mono_mempool_alloc (mp, sizeof (MBTree *));
1409 tbb->instack [0] = t1 = mono_ctree_new_leaf (mp, MB_TERM_EXCEPTION);
1410 t1->data.i = mono_allocate_excvar (cfg);
1411 t1->svt = VAL_POINTER;
1413 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
1414 tbb = &cfg->bblocks [bcinfo [clause->token_or_filter].block_id];
1416 tbb->instack = mono_mempool_alloc (mp, sizeof (MBTree *));
1418 tbb->instack [0] = t1 = mono_ctree_new_leaf (mp, MB_TERM_EXCEPTION);
1419 t1->data.i = mono_allocate_excvar (cfg);
1420 t1->svt = VAL_POINTER;
1423 } else if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
1424 mark_reached (cfg, tbb, NULL, 0);
1426 g_warning ("implement me");
1427 g_assert_not_reached ();
1435 superblock_end = TRUE;
1438 //printf ("START\n");
1439 for (i = 0; i < cfg->block_count; i++) {
1440 bb = &cfg->bblocks [i];
1442 //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);
1444 if (!bb->reached && !superblock_end) {
1445 MonoBBlock *sbb = &cfg->bblocks [i - 1];
1447 g_assert (sbb->outdepth == (sp - stack));
1449 mark_reached (cfg, bb, sbb->outstack, sbb->outdepth);
1454 if (!bb->finished) {
1458 for (j = 0; j < bb->indepth; j++) {
1459 sp [j] = bb->instack [j];
1465 ip = header->code + bb->cli_addr;
1466 end = ip + bb->length;
1468 forest = bb->forest;
1470 superblock_end = FALSE;
1472 tail_recursion = FALSE;
1474 while (inline_list || ip < end) {
1478 MonoInlineInfo *ii = (MonoInlineInfo *)inline_list->data;
1479 if (ip >= ii->end) {
1480 inline_list = g_list_remove_link (inline_list, inline_list);
1482 tail_recursion = FALSE;
1483 image = ii->saved_image;
1485 arg_map = ((MonoInlineInfo *)inline_list->data)->arg_map;
1491 cli_addr = ip - header->code;
1494 //if (inline_list) printf ("INLINE IL%04x OPCODE %s\n", cli_addr, mono_opcode_names [*ip]);
1496 //printf ("%d IL%04x OPCODE %s %d %d %d\n", i, cli_addr, mono_opcode_names [*ip],
1497 //forest->len, superblock_end, sp - stack);
1504 t1 = mono_ctree_new (mp, MB_TERM_THROW, *sp, NULL);
1505 ADD_TREE (t1, cli_addr);
1506 superblock_end = TRUE;
1515 token = read32 (ip);
1518 if (method->wrapper_type != MONO_WRAPPER_NONE)
1519 c = (MonoClass *)mono_method_get_wrapper_data (method, token);
1521 c = mono_class_get (image, token);
1523 t1 = mono_ctree_new_leaf (mp, MB_TERM_NEWOBJ);
1525 t1->svt = VAL_POINTER;
1527 t1 = mono_store_tree (cfg, -1, t1, &t3);
1529 ADD_TREE (t1, cli_addr);
1531 t1 = ctree_create_dup (mp, t3);
1532 t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1533 t2->data.i = sizeof (MonoObject);
1534 t1 = mono_ctree_new (mp, MB_TERM_ADD, t1, t2);
1536 t1 = ctree_create_store (cfg, &c->byval_arg, t1, *sp, FALSE);
1537 ADD_TREE (t1, cli_addr);
1539 PUSH_TREE (t3, VAL_POINTER);
1548 token = read32 (ip);
1552 if (method->wrapper_type != MONO_WRAPPER_NONE)
1553 class = (MonoClass *)mono_method_get_wrapper_data (method, token);
1555 class = mono_class_get (image, token);
1557 t1 = mono_ctree_new (mp, MB_TERM_UNBOX, *sp, NULL);
1558 t1->data.klass = class;
1560 PUSH_TREE (t1, VAL_POINTER);
1567 t1 = mono_ctree_new (mp, MB_TERM_LDLEN, *sp, NULL);
1568 PUSH_TREE (t1, VAL_I32);
1577 token = read32 (ip);
1581 if (method->wrapper_type != MONO_WRAPPER_NONE)
1582 c = (MonoClass *)mono_method_get_wrapper_data (method, token);
1584 c = mono_class_get (image, token);
1585 g_assert (c->valuetype);
1587 t1 = ctree_create_load (cfg, &c->byval_arg, *sp, &svt, FALSE);
1588 PUSH_TREE (t1, svt);
1597 token = read32 (ip);
1601 c = mono_class_get (image, token);
1602 g_assert (c->valuetype);
1604 size = mono_class_value_size (c, NULL);
1606 t1 = mono_ctree_new (mp, MB_TERM_STIND_OBJ, sp [0], sp [1]);
1608 ADD_TREE (t1, cli_addr);
1616 ind = mono_metadata_token_index (read32 (ip));
1619 if (cfg->share_code) {
1620 t1 = mono_ctree_new_leaf (mp, MB_TERM_LDSTR);
1623 o = (MonoObject *) mono_ldstr (cfg->domain, image, ind);
1624 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1628 PUSH_TREE (t1, VAL_POINTER);
1634 MonoClassField *field;
1636 int load_addr = *ip == CEE_LDSFLDA;
1639 token = read32 (ip);
1642 /* need to handle fieldrefs */
1643 field = mono_field_from_token (image, token, &klass);
1646 if (cfg->share_code) {
1647 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1648 t1->data.i = field->offset;
1649 t1 = mono_ctree_new (mp, MB_TERM_LDSFLDA, t1, NULL);
1650 t1->data.klass = klass;
1652 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
1653 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
1654 t1->data.p = (char*)(vt->data) + field->offset;
1660 t1 = ctree_create_load (cfg, field->type, t1, &svt, FALSE);
1663 PUSH_TREE (t1, svt);
1669 MonoClassField *field;
1671 int load_addr = *ip == CEE_LDFLDA;
1674 token = read32 (ip);
1678 /* need to handle fieldrefs */
1679 field = mono_field_from_token (image, token, &klass);
1682 if (klass->marshalbyref) {
1683 t1 = mono_ctree_new (mp, MB_TERM_REMOTE_LDFLDA, sp [0], NULL);
1684 t1->data.fi.klass = klass;
1685 t1->data.fi.field = field;
1687 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1689 if (klass->valuetype)
1690 t1->data.i = field->offset - sizeof (MonoObject);
1692 t1->data.i = field->offset;
1694 t1 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], t1);
1698 t1 = ctree_create_load (cfg, field->type, t1, &svt, FALSE);
1702 PUSH_TREE (t1, svt);
1707 MonoClassField *field;
1711 token = read32 (ip);
1715 /* need to handle fieldrefs */
1716 field = mono_field_from_token (image, token, &klass);
1719 if (cfg->share_code) {
1720 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1721 t1->data.i = field->offset;
1722 t1 = mono_ctree_new (mp, MB_TERM_LDSFLDA, t1, NULL);
1723 t1->data.klass = klass;
1725 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
1726 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
1727 t1->data.p = (char*)(vt->data) + field->offset;
1729 t1 = ctree_create_store (cfg, field->type, t1, *sp, FALSE);
1731 ADD_TREE (t1, cli_addr);
1736 MonoClassField *field;
1740 token = read32 (ip);
1744 /* need to handle fieldrefs */
1745 field = mono_field_from_token (image, token, &klass);
1748 if (klass->marshalbyref) {
1749 t1 = mono_ctree_new (mp, mono_map_remote_stind_type (field->type), sp [0], sp [1]);
1750 t1->data.fi.klass = klass;
1751 t1->data.fi.field = field;
1753 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1754 t1->data.i = klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset;
1755 t1 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], t1);
1756 t1 = mono_ctree_new (mp, MB_TERM_CHECKTHIS, t1, NULL);
1757 t1 = ctree_create_store (cfg, field->type, t1, sp [1], FALSE);
1760 ADD_TREE (t1, cli_addr);
1765 guint32 esize, token;
1768 token = read32 (ip);
1772 class = mono_class_get (image, token);
1774 mono_class_init (class);
1776 esize = mono_class_array_element_size (class);
1778 t1 = mono_ctree_new (mp, MB_TERM_LDELEMA, sp [0], sp [1]);
1780 PUSH_TREE (t1, VAL_POINTER);
1789 t1 = mono_ctree_new_leaf (mp, MB_TERM_BREAK);
1790 ADD_TREE (t1, cli_addr);
1803 t1 = mono_ctree_new (mp, MB_TERM_SWITCH, *sp, NULL);
1804 jt = t1->data.p = mono_alloc_static (sizeof (gpointer) * (n + 2));
1805 st = cli_addr + 5 + 4 * n;
1807 // hack: we store n at position 0
1808 jt [0] = (MonoBBlock *)n;
1810 create_outstack (cfg, bb, stack, sp - stack);
1812 for (k = 1; k <= (n + 1); k++) {
1816 target = read32 (ip) + st;
1819 g_assert (target >= 0 && target <= header->code_size);
1820 g_assert (bcinfo [target].is_block_start);
1821 tbb = &cfg->bblocks [bcinfo [target].block_id];
1822 mark_reached (cfg, tbb, stack, sp - stack);
1826 ADD_TREE (t1, cli_addr);
1831 MonoClass *handle_class;
1832 MonoMethod *next_method;
1835 handle = mono_ldtoken (image, read32 (ip), &handle_class);
1838 if (!cfg->share_code && (*ip == CEE_CALL) && (next_method = mono_get_method (image, read32 (ip+1), NULL)) &&
1839 (next_method->klass == mono_defaults.monotype_class->parent) &&
1840 (strcmp (next_method->name, "GetTypeFromHandle") == 0)) {
1841 MonoClass *tclass = mono_class_from_mono_type (handle);
1842 mono_class_init (tclass);
1844 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1845 t1->data.p = mono_type_get_object (cfg->domain, handle);
1847 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1848 t1->data.p = handle;
1850 PUSH_TREE (t1, VAL_POINTER);
1860 token = read32 (ip);
1863 if (method->wrapper_type != MONO_WRAPPER_NONE)
1864 class = (MonoClass *)mono_method_get_wrapper_data (method, token);
1866 class = mono_class_get (image, token);
1868 if (cfg->share_code) {
1869 t1 = mono_ctree_new (mp, MB_TERM_NEWARR, *sp, NULL);
1873 MonoClass *ac = mono_array_class_get (&class->byval_arg, 1);
1874 MonoVTable *vt = mono_class_vtable (cfg->domain, ac);
1876 t1 = mono_ctree_new (mp, MB_TERM_NEWARR_SPEC, *sp, NULL);
1880 PUSH_TREE (t1, VAL_POINTER);
1888 token = read32 (ip);
1889 class = mono_class_get (image, token);
1893 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1894 t1->data.i = mono_class_value_size (class, NULL);
1895 t1 = mono_ctree_new (mp, MB_TERM_CPSRC, sp [1], t1);
1896 t1 = mono_ctree_new (mp, MB_TERM_CPBLK, sp [0], t1);
1897 ADD_TREE (t1, cli_addr);
1902 MonoMethodSignature *csig;
1904 MBTree *this = NULL;
1911 token = read32 (ip);
1914 if (method->wrapper_type != MONO_WRAPPER_NONE)
1915 cm = mono_method_get_wrapper_data (method, token);
1917 cm = mono_get_method (image, token, NULL);
1919 g_assert (!strcmp (cm->name, ".ctor"));
1921 csig = cm->signature;
1922 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
1923 g_assert (csig->hasthis);
1925 arg_sp = sp -= csig->param_count;
1927 if (!cm->klass->inited)
1928 mono_class_init (cm->klass);
1930 if (cm->klass->parent == mono_defaults.array_class) {
1932 this = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1934 } else if (cm->string_ctor) {
1935 static MonoString *string_dummy = NULL;
1938 string_dummy = mono_string_new_wrapper ("dummy");
1941 /* we just pass a dummy as this, it is not used */
1942 this = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1943 this->data.p = string_dummy;
1945 if (cm->klass->valuetype) {
1946 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1947 t1->data.i = mono_class_value_size (cm->klass, NULL);
1948 this = mono_ctree_new (mp, MB_TERM_LOCALLOC, t1, NULL);
1949 this->data.i = TRUE;
1950 } else if (cfg->share_code) {
1951 this = mono_ctree_new_leaf (mp, MB_TERM_NEWOBJ);
1952 this->data.klass = cm->klass;
1954 MonoVTable *vt = mono_class_vtable (cfg->domain, cm->klass);
1955 this = mono_ctree_new_leaf (mp, MB_TERM_NEWOBJ_SPEC);
1959 this->svt = VAL_POINTER;
1961 t1 = mono_store_tree (cfg, -1, this, &this);
1963 ADD_TREE (t1, cli_addr);
1966 if (csig->param_count + 1 < 10)
1967 arg_info = default_arg_info;
1969 arg_info = g_new (MonoJitArgumentInfo, csig->param_count + 1);
1971 frame_size = arch_get_argument_info (csig, csig->param_count, arg_info);
1973 for (k = csig->param_count - 1; k >= 0; k--) {
1974 t1 = mono_ctree_new (mp, mono_map_arg_type (csig->params [k]), arg_sp [k], NULL);
1975 t1->data.arg_info = arg_info [k + 1];
1976 ADD_TREE (t1, cli_addr);
1979 if (newarr || newstr) {
1981 t2 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
1983 t2->data.p = mono_array_new_va;
1985 t2->data.p = arch_create_jit_trampoline (cm);
1988 t1 = mono_ctree_new (mp, MB_TERM_CALL_I4, this, t2);
1989 t1->data.call_info.pad = arg_info [0].pad;
1990 t1->data.call_info.frame_size = frame_size;
1991 t1->svt = VAL_POINTER;
1993 t1 = mono_store_tree (cfg, -1, t1, &t2);
1995 ADD_TREE (t1, cli_addr);
1996 PUSH_TREE (t2, t2->svt);
2000 t2 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
2001 t2->data.p = arch_create_jit_trampoline (cm);
2003 t1 = mono_ctree_new (mp, mono_map_call_type (csig->ret, &svt), this, t2);
2004 t1->data.call_info.pad = arg_info [0].pad;
2005 t1->data.call_info.frame_size = frame_size;
2008 ADD_TREE (t1, cli_addr);
2010 t1 = ctree_create_dup (mp, this);
2012 if (cm->klass->valuetype) {
2013 t2 = ctree_create_load (cfg, &cm->klass->byval_arg, t1, &svt, FALSE);
2014 PUSH_TREE (t2, svt);
2016 PUSH_TREE (t1, t1->svt);
2020 if (csig->param_count > 9)
2027 case CEE_CALLVIRT: {
2028 MonoMethodSignature *csig;
2030 MBTree *ftn, *this = NULL;
2033 int virtual = *ip == CEE_CALLVIRT;
2034 int calli = *ip == CEE_CALLI;
2036 /* fixme: compute this value */
2037 gboolean shared_to_unshared_call = FALSE;
2038 int nargs, vtype_num = 0;
2041 token = read32 (ip);
2044 tail_recursion = FALSE;
2049 if (method->wrapper_type != MONO_WRAPPER_NONE)
2050 csig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
2052 csig = mono_metadata_parse_signature (image, token);
2055 arg_sp = sp -= csig->param_count;
2057 cm = mono_get_method (image, token, NULL);
2060 if (cm->klass == mono_defaults.math_class &&
2061 cm->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
2063 if (!strcmp (cm->name, "Sin")) {
2065 t1 = mono_ctree_new (mp, MB_TERM_SIN, *sp, NULL);
2066 PUSH_TREE (t1, VAL_DOUBLE);
2068 } else if (!strcmp (cm->name, "Cos")) {
2070 t1 = mono_ctree_new (mp, MB_TERM_COS, *sp, NULL);
2071 PUSH_TREE (t1, VAL_DOUBLE);
2073 } else if (!strcmp (cm->name, "Sqrt")) {
2075 t1 = mono_ctree_new (mp, MB_TERM_SQRT, *sp, NULL);
2076 PUSH_TREE (t1, VAL_DOUBLE);
2081 if (cm->string_ctor)
2082 g_assert_not_reached ();
2084 arg_sp = sp -= cm->signature->param_count;
2086 if ((cm->flags & METHOD_ATTRIBUTE_FINAL &&
2087 cm->klass != mono_defaults.object_class) ||
2088 !(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
2092 g_assert (sp >= stack);
2094 if (!calli && mono_jit_inline_code && !virtual && cm->inline_count != -1 &&
2095 cm != method && (cm->inline_info || check_inlining (cm) >= 0)) {
2096 MonoInlineInfo *ii = alloca (sizeof (MonoInlineInfo));
2100 /* avoid recursive inlining */
2101 for (l = inline_list; l; l = l->next) {
2102 if (((MonoInlineInfo *)l->data)->method == cm)
2108 /* make sure runtime_init is called */
2109 mono_class_vtable (cfg->domain, cm->klass);
2111 mono_jit_stats.inlined_methods++;
2113 if (cm->signature->hasthis)
2116 args = cm->signature->param_count + cm->signature->hasthis;
2120 ii->saved_image = image;
2121 ii->arg_map = alloca (args * sizeof (MBTree *));
2122 memcpy (ii->arg_map, sp, args * sizeof (MBTree *));
2124 if (cm->signature->hasthis && !cm->uses_this &&
2125 (ii->arg_map [0]->op != MB_TERM_CHECKTHIS)) {
2126 ii->arg_map [0] = mono_ctree_new (mp, MB_TERM_CHECKTHIS,
2127 ii->arg_map [0], NULL);
2128 ADD_TREE (ii->arg_map [0], ii->arg_map [0]->cli_addr);
2131 if (cm->inline_count) {
2132 inline_list = g_list_prepend (inline_list, ii);
2133 ip = ((MonoMethodNormal *)cm)->header->code;
2134 ii->end = ip + cm->inline_count;
2135 arg_map = ii->arg_map;
2136 image = cm->klass->image;
2143 csig = cm->signature;
2145 nargs = csig->param_count;
2147 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
2148 g_assert (!virtual || csig->hasthis);
2150 if (!calli && cm->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
2151 if (cm->klass->parent == mono_defaults.array_class) {
2152 array_rank = cm->klass->rank;
2154 if (cm->name [0] == 'S') /* Set */
2159 if (csig->param_count + 1 < 10)
2160 arg_info = default_arg_info;
2162 arg_info = g_new (MonoJitArgumentInfo, csig->param_count + 1);
2164 frame_size = arch_get_argument_info (csig, nargs, arg_info);
2166 for (k = nargs - 1; k >= 0; k--) {
2167 g_assert (arg_sp [k]);
2168 t1 = mono_ctree_new (mp, mono_map_arg_type (csig->params [k]), arg_sp [k], NULL);
2169 t1->data.arg_info = arg_info [k + 1];
2170 ADD_TREE (t1, arg_sp [k]->cli_addr);
2176 this = mono_ctree_new_leaf (mp, MB_TERM_NOP);
2179 if (MONO_TYPE_ISSTRUCT (csig->ret) && !array_rank) {
2182 size = mono_class_native_size (csig->ret->data.klass, &align);
2184 size = mono_class_value_size (csig->ret->data.klass, &align);
2186 vtype_num = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, VAL_UNKNOWN);
2191 t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2192 t2->data.p = ves_array_element_address;
2194 t1 = mono_ctree_new (mp, MB_TERM_CALL_I4, this, t2);
2195 t1->data.call_info.vtype_num = vtype_num;
2196 t1->data.call_info.frame_size = frame_size;
2197 t1->data.call_info.pad = arg_info [0].pad;
2198 t1->svt = VAL_POINTER;
2200 t1 = mono_store_tree (cfg, -1, t1, &t2);
2202 ADD_TREE (t1, cli_addr);
2204 if (cm->name [0] == 'G') { /* Get */
2205 t1 = mono_ctree_new (mp, mono_map_ldind_type (csig->ret, &svt), t2, NULL);
2207 PUSH_TREE (t1, t1->svt);
2208 } else if (cm->name [0] == 'S') { /* Set */
2209 t1 = ctree_create_store (cfg, csig->params [nargs], t2, arg_sp [nargs], FALSE);
2210 ADD_TREE (t1, cli_addr);
2211 } else if (cm->name [0] == 'A') { /* Address */
2212 PUSH_TREE (t2, t1->svt);
2214 g_assert_not_reached ();
2221 } else if (virtual || (csig->hasthis &&
2222 !(cm->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
2223 (cm->klass->marshalbyref || shared_to_unshared_call))) {
2225 mono_class_init (cm->klass);
2227 if (cm->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
2228 t2 = mono_ctree_new_leaf (mp, MB_TERM_INTF_ADDR);
2230 t2 = mono_ctree_new_leaf (mp, MB_TERM_VFUNC_ADDR);
2235 t2 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
2236 t2->data.p = arch_create_jit_trampoline (cm);
2240 t1 = mono_ctree_new (mp, mono_map_call_type (csig->ret, &svt), this, t2);
2241 t1->data.call_info.vtype_num = vtype_num;
2242 t1->data.call_info.frame_size = frame_size;
2243 t1->data.call_info.pad = arg_info [0].pad;
2246 if (csig->ret->type != MONO_TYPE_VOID) {
2249 ADD_TREE (t1, cli_addr);
2250 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2251 t1->data.i = vtype_num;
2252 PUSH_TREE (t1, VAL_POINTER);
2254 t1 = mono_store_tree (cfg, -1, t1, &t2);
2256 ADD_TREE (t1, cli_addr);
2257 PUSH_TREE (t2, t2->svt);
2260 ADD_TREE (t1, cli_addr);
2263 if (csig->param_count > 9)
2272 token = read32 (ip);
2275 c = mono_class_get (image, token);
2277 mono_class_init (c);
2279 t1 = mono_ctree_new (mp, MB_TERM_ISINST, *sp, NULL);
2282 PUSH_TREE (t1, VAL_POINTER);
2287 case CEE_CASTCLASS: {
2291 token = read32 (ip);
2294 c = mono_class_get (image, token);
2296 mono_class_init (c);
2298 t1 = mono_ctree_new (mp, MB_TERM_CASTCLASS, *sp, NULL);
2301 PUSH_TREE (t1, VAL_POINTER);
2306 case CEE_LDC_I4_S: {
2308 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2309 t1->data.i = *(const gint8 *)ip;
2311 PUSH_TREE (t1, VAL_I32);
2316 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2317 t1->data.i = read32 (ip);
2319 PUSH_TREE (t1, VAL_I32);
2331 case CEE_LDC_I4_8: {
2332 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2333 t1->data.i = (*ip) - CEE_LDC_I4_0;
2335 PUSH_TREE (t1, VAL_I32);
2339 //fixme: don't know if this is portable ?
2341 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2343 PUSH_TREE (t1, VAL_POINTER);
2348 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I8);
2349 t1->data.l = read64 (ip);
2351 PUSH_TREE (t1, VAL_I64);
2355 float *f = mono_alloc_static (sizeof (float));
2357 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_R4);
2361 PUSH_TREE (t1, VAL_DOUBLE);
2365 double *d = mono_alloc_static (sizeof (double));
2367 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_R8);
2371 PUSH_TREE (t1, VAL_DOUBLE);
2378 int n = (*ip) - CEE_LDLOC_0;
2381 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2382 t1->data.i = LOCAL_POS (n);
2383 if (!MONO_TYPE_ISSTRUCT (LOCAL_TYPE (n)))
2384 t1 = ctree_create_load (cfg, LOCAL_TYPE (n), t1, &svt, FALSE);
2385 PUSH_TREE (t1, svt);
2391 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2392 t1->data.i = LOCAL_POS (*ip);
2393 if (!MONO_TYPE_ISSTRUCT (LOCAL_TYPE (*ip)))
2394 t1 = ctree_create_load (cfg, LOCAL_TYPE (*ip), t1, &svt, FALSE);
2397 PUSH_TREE (t1, svt);
2400 case CEE_LDLOCA_S: {
2403 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2404 t1->data.i = LOCAL_POS (*ip);
2405 VARINFO (cfg, t1->data.i).isvolatile = 1;
2407 PUSH_TREE (t1, VAL_POINTER);
2414 int n = (*ip) - CEE_STLOC_0;
2418 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2419 t1->data.i = LOCAL_POS (n);
2421 if ((t2 = mono_stack_duplicate_used_var (cfg, stack, sp, t1->data.i)))
2422 ADD_TREE (t2, cli_addr);
2424 t1 = ctree_create_store (cfg, LOCAL_TYPE (n), t1, *sp, FALSE);
2425 ADD_TREE (t1, cli_addr);
2432 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2433 t1->data.i = LOCAL_POS (*ip);
2434 if ((t2 = mono_stack_duplicate_used_var (cfg, stack, sp, t1->data.i)))
2435 ADD_TREE (t2, cli_addr);
2437 t1 = ctree_create_store (cfg, LOCAL_TYPE (*ip), t1, *sp, FALSE);
2439 ADD_TREE (t1, cli_addr);
2446 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4)
2447 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i + sp [1]->data.i);
2449 t1 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], sp [1]);
2450 PUSH_TREE (t1, sp [0]->svt);
2457 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4)
2458 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i - sp [1]->data.i);
2460 t1 = mono_ctree_new (mp, MB_TERM_SUB, sp [0], sp [1]);
2461 PUSH_TREE (t1, sp [0]->svt);
2468 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4)
2469 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i & sp [1]->data.i);
2471 t1 = mono_ctree_new (mp, MB_TERM_AND, sp [0], sp [1]);
2472 PUSH_TREE (t1, sp [0]->svt);
2479 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4)
2480 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i | sp [1]->data.i);
2482 t1 = mono_ctree_new (mp, MB_TERM_OR, sp [0], sp [1]);
2483 PUSH_TREE (t1, sp [0]->svt);
2490 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4)
2491 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i ^ sp [1]->data.i);
2493 t1 = mono_ctree_new (mp, MB_TERM_XOR, sp [0], sp [1]);
2494 PUSH_TREE (t1, sp [0]->svt);
2501 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4) {
2502 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i * sp [1]->data.i);
2503 PUSH_TREE (t1, sp [0]->svt);
2505 MAKE_SPILLED_BI_ALU1 (MUL, sp [0], sp [1])
2513 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4
2514 && (sp[1]->data.i != 0)
2515 && ((sp[0]->data.i != 0x080000000) || (sp[1]->data.i != -1))) {
2516 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i / sp [1]->data.i);
2517 PUSH_TREE (t1, sp [0]->svt);
2519 MAKE_SPILLED_BI_ALU1 (DIV, sp [0], sp [1])
2527 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4) {
2528 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i % sp [1]->data.i);
2529 PUSH_TREE (t1, sp [0]->svt);
2531 MAKE_SPILLED_BI_ALU1 (REM, sp [0], sp [1])
2539 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4) {
2540 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i << sp [1]->data.i);
2541 PUSH_TREE (t1, sp [0]->svt);
2543 MAKE_SPILLED_BI_ALU1 (SHL, sp [0], sp [1])
2551 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4) {
2552 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i >> sp [1]->data.i);
2553 PUSH_TREE (t1, sp [0]->svt);
2555 MAKE_SPILLED_BI_ALU1 (SHR, sp [0], sp [1])
2560 MAKE_BI_ALU (ADD_OVF)
2561 MAKE_BI_ALU (ADD_OVF_UN)
2562 MAKE_BI_ALU (SUB_OVF)
2563 MAKE_BI_ALU (SUB_OVF_UN)
2564 MAKE_SPILLED_BI_ALU (SHR_UN)
2565 MAKE_SPILLED_BI_ALU (MUL_OVF)
2566 MAKE_SPILLED_BI_ALU (MUL_OVF_UN)
2567 MAKE_SPILLED_BI_ALU (DIV_UN)
2568 MAKE_SPILLED_BI_ALU (REM_UN)
2570 MAKE_LDIND (LDIND_I1, MB_TERM_LDIND_I1, VAL_I32)
2571 MAKE_LDIND (LDIND_U1, MB_TERM_LDIND_U1, VAL_I32)
2572 MAKE_LDIND (LDIND_I2, MB_TERM_LDIND_I2, VAL_I32)
2573 MAKE_LDIND (LDIND_U2, MB_TERM_LDIND_U2, VAL_I32)
2574 MAKE_LDIND (LDIND_I, MB_TERM_LDIND_I4, VAL_I32)
2575 MAKE_LDIND (LDIND_I4, MB_TERM_LDIND_I4, VAL_I32)
2576 MAKE_LDIND (LDIND_REF, MB_TERM_LDIND_REF, VAL_POINTER)
2577 MAKE_LDIND (LDIND_U4, MB_TERM_LDIND_U4, VAL_I32)
2578 MAKE_LDIND (LDIND_I8, MB_TERM_LDIND_I8, VAL_I64)
2579 MAKE_LDIND (LDIND_R4, MB_TERM_LDIND_R4, VAL_DOUBLE)
2580 MAKE_LDIND (LDIND_R8, MB_TERM_LDIND_R8, VAL_DOUBLE)
2582 MAKE_STIND (STIND_I1, MB_TERM_STIND_I1)
2583 MAKE_STIND (STIND_I2, MB_TERM_STIND_I2)
2584 MAKE_STIND (STIND_I, MB_TERM_STIND_I4)
2585 MAKE_STIND (STIND_I4, MB_TERM_STIND_I4)
2586 MAKE_STIND (STIND_I8, MB_TERM_STIND_I8)
2587 MAKE_STIND (STIND_R4, MB_TERM_STIND_R4)
2588 MAKE_STIND (STIND_R8, MB_TERM_STIND_R8)
2589 MAKE_STIND (STIND_REF, MB_TERM_STIND_REF)
2591 MAKE_LDELEM (LDELEM_I1, MB_TERM_LDIND_I1, VAL_I32, 1)
2592 MAKE_LDELEM (LDELEM_U1, MB_TERM_LDIND_U1, VAL_I32, 1)
2593 MAKE_LDELEM (LDELEM_I2, MB_TERM_LDIND_I2, VAL_I32, 2)
2594 MAKE_LDELEM (LDELEM_U2, MB_TERM_LDIND_U2, VAL_I32, 2)
2595 MAKE_LDELEM (LDELEM_I, MB_TERM_LDIND_I4, VAL_I32, 4)
2596 MAKE_LDELEM (LDELEM_I4, MB_TERM_LDIND_I4, VAL_I32, 4)
2597 MAKE_LDELEM (LDELEM_REF, MB_TERM_LDIND_REF, VAL_POINTER, sizeof (gpointer))
2598 MAKE_LDELEM (LDELEM_U4, MB_TERM_LDIND_U4, VAL_I32, 4)
2599 MAKE_LDELEM (LDELEM_I8, MB_TERM_LDIND_I8, VAL_I64, 8)
2600 MAKE_LDELEM (LDELEM_R4, MB_TERM_LDIND_R4, VAL_DOUBLE, 4)
2601 MAKE_LDELEM (LDELEM_R8, MB_TERM_LDIND_R8, VAL_DOUBLE, 8)
2603 MAKE_STELEM (STELEM_I1, MB_TERM_STIND_I1, 1)
2604 MAKE_STELEM (STELEM_I2, MB_TERM_STIND_I2, 2)
2605 MAKE_STELEM (STELEM_I4, MB_TERM_STIND_I4, 4)
2606 MAKE_STELEM (STELEM_I, MB_TERM_STIND_I4, 4)
2607 MAKE_STELEM (STELEM_REF, MB_TERM_STIND_REF, sizeof (gpointer))
2608 MAKE_STELEM (STELEM_I8, MB_TERM_STIND_I8, 8)
2609 MAKE_STELEM (STELEM_R4, MB_TERM_STIND_R4, 4)
2610 MAKE_STELEM (STELEM_R8, MB_TERM_STIND_R8, 8)
2615 if (sp [0]->op == MB_TERM_CONST_I4)
2616 t1 = mono_ctree_new_icon4 (mp, -sp [0]->data.i);
2618 t1 = mono_ctree_new (mp, MB_TERM_NEG, sp [0], NULL);
2619 PUSH_TREE (t1, sp [0]->svt);
2625 if (sp [0]->op == MB_TERM_CONST_I4)
2626 t1 = mono_ctree_new_icon4 (mp, ~sp [0]->data.i);
2628 t1 = mono_ctree_new (mp, MB_TERM_NOT, sp [0], NULL);
2629 PUSH_TREE (t1, sp [0]->svt);
2635 int br_s = (*ip == CEE_BR_S);
2639 target = cli_addr + 2 + (signed char) *ip;
2641 target = cli_addr + 5 + (gint32) read32(ip);
2643 g_assert (target >= 0 && target <= header->code_size);
2644 g_assert (bcinfo [target].is_block_start);
2645 tbb = &cfg->bblocks [bcinfo [target].block_id];
2646 create_outstack (cfg, bb, stack, sp - stack);
2647 mark_reached (cfg, tbb, bb->outstack, bb->outdepth);
2649 t1 = mono_ctree_new_leaf (mp, MB_TERM_BR);
2651 ADD_TREE (t1, cli_addr);
2658 superblock_end = TRUE;
2665 token = read32 (ip);
2668 cm = mono_get_method (method->klass->image, token, NULL);
2671 t1 = mono_ctree_new_leaf (mp, MB_TERM_JMP);
2672 /* fixme: our magic trampoline code does not work in this case,
2673 * so I need to compile the method immediately */
2674 t1->data.p = mono_compile_method (cm);;
2676 ADD_TREE (t1, cli_addr);
2683 int leave_s = (*ip == CEE_LEAVE_S);
2687 target = cli_addr + 2 + (signed char) *ip;
2689 target = cli_addr + 5 + (gint32) read32(ip);
2691 g_assert (target >= 0 && target <= header->code_size);
2692 g_assert (bcinfo [target].is_block_start);
2693 tbb = &cfg->bblocks [bcinfo [target].block_id];
2695 /* empty the stack */
2696 while (sp != stack) {
2698 t1 = mono_ctree_new (mp, MB_TERM_POP, *sp, NULL);
2699 ADD_TREE (t1, cli_addr);
2702 mark_reached (cfg, tbb, NULL, 0);
2704 /* fixme: fault handler */
2706 if ((hb = mono_find_final_block (cfg, cli_addr, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
2707 mark_reached (cfg, hb, NULL, 0);
2708 t1 = mono_ctree_new_leaf (mp, MB_TERM_HANDLER);
2710 ADD_TREE (t1, cli_addr);
2713 /* check if we leave a catch handler, if so we have to
2714 * rethrow ThreadAbort exceptions */
2715 for (k = 0; k < header->num_clauses; ++k) {
2716 MonoExceptionClause *clause = &header->clauses [k];
2717 if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE &&
2718 MONO_OFFSET_IN_HANDLER (clause, cli_addr)) {
2719 t1 = mono_ctree_new_leaf (mp, MB_TERM_RETHROW_ABORT);
2720 t1->data.i = mono_allocate_excvar (cfg);
2721 ADD_TREE (t1, cli_addr);
2726 t1 = mono_ctree_new_leaf (mp, MB_TERM_BR);
2728 ADD_TREE (t1, cli_addr);
2735 superblock_end = TRUE;
2752 case CEE_BRTRUE_S: {
2754 int near_jump = *ip == CEE_BRTRUE_S;
2758 t1 = mono_ctree_new (mp, MB_TERM_BRTRUE, sp [0], NULL);
2761 target = cli_addr + 2 + (signed char) *ip;
2763 target = cli_addr + 5 + (gint32) read32 (ip);
2765 g_assert (target >= 0 && target <= header->code_size);
2766 g_assert (bcinfo [target].is_block_start);
2767 tbb = &cfg->bblocks [bcinfo [target].block_id];
2768 create_outstack (cfg, bb, stack, sp - stack);
2769 mark_reached (cfg, tbb, bb->outstack, bb->outdepth);
2772 ip += near_jump ? 1: 4;
2773 ADD_TREE (t1, cli_addr);
2777 case CEE_BRFALSE_S: {
2779 int near_jump = *ip == CEE_BRFALSE_S;
2783 t1 = mono_ctree_new (mp, MB_TERM_BRFALSE, sp [0], NULL);
2786 target = cli_addr + 2 + (signed char) *ip;
2788 target = cli_addr + 5 + (gint32) read32 (ip);
2790 g_assert (target >= 0 && target <= header->code_size);
2791 g_assert (bcinfo [target].is_block_start);
2792 tbb = &cfg->bblocks [bcinfo [target].block_id];
2793 create_outstack (cfg, bb, stack, sp - stack);
2794 mark_reached (cfg, tbb, bb->outstack, bb->outdepth);
2797 ip += near_jump ? 1: 4;
2798 ADD_TREE (t1, cli_addr);
2802 MonoType *ret = signature->ret;
2806 if (ret->type != MONO_TYPE_VOID) {
2808 if (MONO_TYPE_ISSTRUCT (ret)) {
2810 t1 = mono_ctree_new (mp, MB_TERM_RET_OBJ, *sp, NULL);
2811 t1->data.i = mono_class_value_size (ret->data.klass, &align);
2813 t1 = mono_ctree_new (mp, MB_TERM_RET, *sp, NULL);
2816 t1 = mono_ctree_new_leaf (mp, MB_TERM_RET_VOID);
2819 t1->last_instr = (ip == (header->code + header->code_size));
2821 ADD_TREE (t1, cli_addr);
2824 g_warning ("more values on stack at %s IL_%04x: %d",
2825 mono_method_full_name (method, TRUE),
2826 ip - header->code, sp - stack);
2827 mono_print_ctree (cfg, sp [-1]);
2830 superblock_end = TRUE;
2833 case CEE_ENDFINALLY: {
2836 t1 = mono_ctree_new_leaf (mp, MB_TERM_ENDFINALLY);
2837 ADD_TREE (t1, cli_addr);
2838 t1->last_instr = FALSE;
2840 g_assert (sp == stack);
2841 superblock_end = TRUE;
2848 int n = (*ip) - CEE_LDARG_0;
2855 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2856 t1->data.i = ARG_POS (n);
2857 if (!MONO_TYPE_ISSTRUCT (ARG_TYPE (n)))
2858 t1 = ctree_create_load (cfg, ARG_TYPE (n), t1, &svt, TRUE);
2860 PUSH_TREE (t1, svt);
2869 *sp = arg_map [*ip];
2872 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2873 t1->data.i = ARG_POS (*ip);
2874 if (!MONO_TYPE_ISSTRUCT (ARG_TYPE (*ip)))
2875 t1 = ctree_create_load (cfg, ARG_TYPE (*ip), t1, &svt, TRUE);
2876 PUSH_TREE (t1, svt);
2881 case CEE_LDARGA_S: {
2883 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2884 t1->data.i = ARG_POS (*ip);
2885 PUSH_TREE (t1, VAL_POINTER);
2893 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2894 t1->data.i = ARG_POS (*ip);
2895 t1 = ctree_create_store (cfg, ARG_TYPE (*ip), t1, *sp, TRUE);
2897 ADD_TREE (t1, cli_addr);
2905 /* fixme: maybe we should add more of these optimisations */
2906 if (sp [-1]->op == MB_TERM_CONST_I4) {
2908 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2909 t1->data.i = sp [-1]->data.i;
2910 PUSH_TREE (t1, VAL_I32);
2915 vnum = mono_allocate_intvar (cfg, sp - stack, sp [0]->svt);
2916 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2919 t2 = mono_ctree_new (mp, mono_map_store_svt_type (sp [0]->svt), t1, sp [0]);
2920 t2->svt = sp [0]->svt;
2921 ADD_TREE (t2, cli_addr);
2923 t1 = ctree_create_dup (mp, t2);
2924 PUSH_TREE (t1, t1->svt);
2925 t1 = ctree_create_dup (mp, t1);
2926 PUSH_TREE (t1, t1->svt);
2934 t1 = mono_ctree_new (mp, MB_TERM_POP, *sp, NULL);
2935 ADD_TREE (t1, cli_addr);
2939 case CEE_CKFINITE: {
2944 /* this instr. can throw exceptions as side effect,
2945 * so we cant eliminate dead code which contains CKFINITE opdodes.
2946 * Spilling to memory makes sure that we always perform
2948 vnum = mono_allocate_intvar (cfg, sp - stack, sp [0]->svt);
2949 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2952 t2 = mono_ctree_new (mp, MB_TERM_CKFINITE, *sp, NULL);
2954 t2 = mono_ctree_new (mp, mono_map_store_svt_type (sp [0]->svt), t1, t2);
2955 t2->svt = sp [0]->svt;
2956 ADD_TREE (t2, cli_addr);
2958 t1 = ctree_create_dup (mp, t2);
2959 PUSH_TREE (t1, t1->svt);
2965 if (sp [0]->op == MB_TERM_CONST_I4)
2966 t1 = mono_ctree_new_icon4 (mp, (guint8)sp [0]->data.i);
2968 t1 = mono_ctree_new (mp, MB_TERM_CONV_U1, *sp, NULL);
2969 PUSH_TREE (t1, VAL_I32);
2974 if (sp [0]->op == MB_TERM_CONST_I4)
2975 t1 = mono_ctree_new_icon4 (mp, (gint8)sp [0]->data.i);
2977 t1 = mono_ctree_new (mp, MB_TERM_CONV_I1, *sp, NULL);
2978 PUSH_TREE (t1, VAL_I32);
2983 if (sp [0]->op == MB_TERM_CONST_I4)
2984 t1 = mono_ctree_new_icon4 (mp, (guint16)sp [0]->data.i);
2986 t1 = mono_ctree_new (mp, MB_TERM_CONV_U2, *sp, NULL);
2987 PUSH_TREE (t1, VAL_I32);
2992 if (sp [0]->op == MB_TERM_CONST_I4)
2993 t1 = mono_ctree_new_icon4 (mp, (gint16)sp [0]->data.i);
2995 t1 = mono_ctree_new (mp, MB_TERM_CONV_I2, *sp, NULL);
2996 PUSH_TREE (t1, VAL_I32);
3002 if (sp [0]->op == MB_TERM_CONST_I4)
3005 t1 = mono_ctree_new (mp, MB_TERM_CONV_I4, *sp, NULL);
3006 PUSH_TREE (t1, VAL_I32);
3012 if (sp [0]->op == MB_TERM_CONST_I4)
3015 t1 = mono_ctree_new (mp, MB_TERM_CONV_U4, *sp, NULL);
3016 PUSH_TREE (t1, VAL_I32);
3021 t1 = mono_ctree_new (mp, MB_TERM_CONV_I8, *sp, NULL);
3022 PUSH_TREE (t1, VAL_I64);
3027 t1 = mono_ctree_new (mp, MB_TERM_CONV_U8, *sp, NULL);
3028 PUSH_TREE (t1, VAL_I64);
3033 t1 = mono_ctree_new (mp, MB_TERM_CONV_R8, *sp, NULL);
3034 PUSH_TREE (t1, VAL_DOUBLE);
3039 t1 = mono_ctree_new (mp, MB_TERM_CONV_R4, *sp, NULL);
3040 PUSH_TREE (t1, VAL_DOUBLE);
3045 t1 = mono_ctree_new (mp, MB_TERM_CONV_R_UN, *sp, NULL);
3046 PUSH_TREE (t1, VAL_DOUBLE);
3048 case CEE_CONV_OVF_I:
3049 case CEE_CONV_OVF_I4:
3052 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I4, *sp, NULL);
3053 PUSH_TREE (t1, VAL_I32);
3055 case CEE_CONV_OVF_I_UN:
3056 case CEE_CONV_OVF_I4_UN:
3059 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I4_UN, *sp, NULL);
3060 PUSH_TREE (t1, VAL_I32);
3062 case CEE_CONV_OVF_U:
3063 case CEE_CONV_OVF_U4:
3066 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U4, *sp, NULL);
3067 PUSH_TREE (t1, VAL_I32);
3069 case CEE_CONV_OVF_I1:
3072 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I1, *sp, NULL);
3073 PUSH_TREE (t1, VAL_I32);
3075 case CEE_CONV_OVF_I1_UN:
3078 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I1_UN, *sp, NULL);
3079 PUSH_TREE (t1, VAL_I32);
3081 case CEE_CONV_OVF_U1_UN:
3084 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U1_UN, *sp, NULL);
3085 PUSH_TREE (t1, VAL_I32);
3087 case CEE_CONV_OVF_U1:
3090 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U1, *sp, NULL);
3091 PUSH_TREE (t1, VAL_I32);
3093 case CEE_CONV_OVF_I2:
3096 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I2, *sp, NULL);
3097 PUSH_TREE (t1, VAL_I32);
3099 case CEE_CONV_OVF_U2_UN:
3102 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U2_UN, *sp, NULL);
3103 PUSH_TREE (t1, VAL_I32);
3105 case CEE_CONV_OVF_U2:
3108 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U2, *sp, NULL);
3109 PUSH_TREE (t1, VAL_I32);
3111 case CEE_CONV_OVF_I2_UN:
3114 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I2_UN, *sp, NULL);
3115 PUSH_TREE (t1, VAL_I32);
3117 case CEE_CONV_OVF_U8:
3120 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U8, *sp, NULL);
3121 PUSH_TREE (t1, VAL_I32);
3123 case CEE_CONV_OVF_U_UN:
3124 case CEE_CONV_OVF_U4_UN:
3125 // fixme: raise exceptions ?
3128 t1 = mono_ctree_new (mp, MB_TERM_CONV_I4, *sp, NULL);
3129 PUSH_TREE (t1, VAL_I32);
3131 case CEE_CONV_OVF_I8_UN:
3132 case CEE_CONV_OVF_U8_UN: /* FIXME: slightly incorrect, but non worth fixing the corner cases in the old jit */
3135 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I8_UN, *sp, NULL);
3136 PUSH_TREE (t1, VAL_I64);
3138 case MONO_CUSTOM_PREFIX: {
3142 case CEE_MONO_FUNC1: {
3143 MonoMarshalConv conv;
3151 t1 = mono_ctree_new (mp, MB_TERM_FUNC1, *sp, NULL);
3154 case MONO_MARSHAL_CONV_STR_LPWSTR:
3155 t1->data.p = mono_string_to_utf16;
3157 case MONO_MARSHAL_CONV_LPWSTR_STR:
3158 t1->data.p = mono_string_from_utf16;
3160 case MONO_MARSHAL_CONV_LPSTR_STR:
3161 t1->data.p = mono_string_new_wrapper;
3163 case MONO_MARSHAL_CONV_STR_LPTSTR:
3164 case MONO_MARSHAL_CONV_STR_LPSTR:
3165 t1->data.p = mono_string_to_utf8;
3167 case MONO_MARSHAL_CONV_STR_BSTR:
3168 t1->data.p = mono_string_to_bstr;
3170 case MONO_MARSHAL_CONV_STR_TBSTR:
3171 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
3172 t1->data.p = mono_string_to_ansibstr;
3174 case MONO_MARSHAL_CONV_SB_LPSTR:
3175 t1->data.p = mono_string_builder_to_utf8;
3177 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
3178 t1->data.p = mono_array_to_savearray;
3180 case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
3181 t1->data.p = mono_array_to_lparray;
3183 case MONO_MARSHAL_CONV_DEL_FTN:
3184 t1->data.p = mono_delegate_to_ftnptr;
3186 case MONO_MARSHAL_CONV_STRARRAY_STRLPARRAY:
3187 t1->data.p = mono_marshal_string_array;
3190 g_assert_not_reached ();
3192 PUSH_TREE (t1, VAL_POINTER);
3195 case CEE_MONO_PROC2: {
3196 MonoMarshalConv conv;
3202 t1 = mono_ctree_new (mp, MB_TERM_PROC2, sp [0], sp [1]);
3205 case MONO_MARSHAL_CONV_LPSTR_SB:
3206 t1->data.p = mono_string_utf8_to_builder;
3208 case MONO_MARSHAL_FREE_ARRAY:
3209 t1->data.p = mono_marshal_free_array;
3212 g_assert_not_reached ();
3214 ADD_TREE (t1, cli_addr);
3217 case CEE_MONO_PROC3: {
3218 MonoMarshalConv conv;
3225 t1 = mono_ctree_new (mp, MB_TERM_CPSRC, sp [1], sp [2]);
3226 t1 = mono_ctree_new (mp, MB_TERM_PROC3, sp [0], t1);
3229 case MONO_MARSHAL_CONV_STR_BYVALSTR:
3230 t1->data.p = mono_string_to_byvalstr;
3232 case MONO_MARSHAL_CONV_STR_BYVALWSTR:
3233 t1->data.p = mono_string_to_byvalwstr;
3236 g_assert_not_reached ();
3239 ADD_TREE (t1, cli_addr);
3242 case CEE_MONO_FREE: {
3246 t1 = mono_ctree_new (mp, MB_TERM_FREE, *sp, NULL);
3247 ADD_TREE (t1, cli_addr);
3250 case CEE_MONO_OBJADDR: {
3254 t1 = mono_ctree_new (mp, MB_TERM_OBJADDR, *sp, NULL);
3255 PUSH_TREE (t1, VAL_POINTER);
3258 case CEE_MONO_VTADDR: {
3262 t1 = mono_ctree_new (mp, MB_TERM_VTADDR, *sp, NULL);
3263 PUSH_TREE (t1, VAL_POINTER);
3266 case CEE_MONO_LDPTR: {
3270 token = read32 (ip);
3273 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
3274 t1->data.p = mono_method_get_wrapper_data (method, token);
3276 PUSH_TREE (t1, VAL_POINTER);
3279 case CEE_MONO_NEWOBJ: {
3284 token = read32 (ip);
3287 class = (MonoClass *)mono_method_get_wrapper_data (method, token);
3289 t1 = mono_ctree_new_leaf (mp, MB_TERM_NEWOBJ);
3291 PUSH_TREE (t1, VAL_POINTER);
3295 case CEE_MONO_RETOBJ: {
3296 MonoType *ret = signature->ret;
3301 token = read32 (ip);
3304 class = (MonoClass *)mono_method_get_wrapper_data (method, token);
3308 g_assert (MONO_TYPE_ISSTRUCT (ret));
3310 t1 = ctree_create_load (cfg, &class->byval_arg, *sp, &svt, FALSE);
3311 t1 = mono_ctree_new (mp, MB_TERM_RET_OBJ, t1, NULL);
3313 if (signature->pinvoke)
3314 t1->data.i = mono_class_native_size (ret->data.klass, NULL);
3316 t1->data.i = mono_class_value_size (ret->data.klass, NULL);
3318 t1->last_instr = (ip == (header->code + header->code_size));
3320 ADD_TREE (t1, cli_addr);
3323 g_warning ("more values on stack at %s IL_%04x: %d",
3324 mono_method_full_name (method, TRUE),
3325 ip - header->code, sp - stack);
3326 mono_print_ctree (cfg, sp [-1]);
3329 superblock_end = TRUE;
3333 g_error ("Unimplemented opcode at IL_%04x "
3334 "%02x %02x", ip - header->code, MONO_CUSTOM_PREFIX, *ip);
3342 case CEE_ENDFILTER: {
3346 t1 = mono_ctree_new (mp, MB_TERM_ENDFILTER, *sp, NULL);
3347 ADD_TREE (t1, cli_addr);
3348 t1->last_instr = FALSE;
3350 g_assert (sp == stack);
3351 superblock_end = TRUE;
3360 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3361 t1->data.i = LOCAL_POS (n);
3362 if (!MONO_TYPE_ISSTRUCT (LOCAL_TYPE (n)))
3363 t1 = ctree_create_load (cfg, LOCAL_TYPE (n), t1, &svt, FALSE);
3366 PUSH_TREE (t1, svt);
3372 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3373 t1->data.i = LOCAL_POS (read16 (ip));
3374 VARINFO (cfg, t1->data.i).isvolatile = 1;
3376 PUSH_TREE (t1, VAL_POINTER);
3383 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3384 t1->data.i = LOCAL_POS (read16 (ip));
3385 if ((t2 = mono_stack_duplicate_used_var (cfg, stack, sp, t1->data.i)))
3386 ADD_TREE (t2, cli_addr);
3388 t1 = ctree_create_store (cfg, LOCAL_TYPE (read16 (ip)), t1, *sp, FALSE);
3390 ADD_TREE (t1, cli_addr);
3398 arg_pos = read16 (ip);
3401 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3402 t1->data.i = ARG_POS (arg_pos);
3403 t1 = ctree_create_store (cfg, ARG_TYPE (arg_pos), t1, *sp, TRUE);
3404 ADD_TREE (t1, cli_addr);
3416 t1 = mono_ctree_new_leaf (mp, MB_TERM_RETHROW);
3417 t1->data.i = mono_allocate_excvar (cfg);
3418 ADD_TREE (t1, cli_addr);
3425 token = read32 (ip);
3428 if (method->wrapper_type != MONO_WRAPPER_NONE)
3429 cm = (MonoMethod *)mono_method_get_wrapper_data (method, token);
3431 cm = mono_get_method (image, token, NULL);
3435 t1 = mono_ctree_new_leaf (mp, MB_TERM_LDFTN);
3437 PUSH_TREE (t1, VAL_POINTER);
3440 case CEE_LDVIRTFTN: {
3444 token = read32 (ip);
3448 cm = mono_get_method (image, token, NULL);
3451 if (cm->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
3452 t2 = mono_ctree_new_leaf (mp, MB_TERM_INTF_ADDR);
3454 t2 = mono_ctree_new_leaf (mp, MB_TERM_VFUNC_ADDR);
3458 t1 = mono_ctree_new (mp, MB_TERM_LDVIRTFTN, *sp, t2);
3460 PUSH_TREE (t1, VAL_POINTER);
3469 token = read32 (ip);
3470 class = mono_class_get (image, token);
3474 t1 = mono_ctree_new (mp, MB_TERM_INITOBJ, *sp, NULL);
3475 t1->data.i = mono_class_value_size (class, NULL);
3476 ADD_TREE (t1, cli_addr);
3486 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3487 t1->data.i = ARG_POS (n);
3488 if (!MONO_TYPE_ISSTRUCT (ARG_TYPE (n)))
3489 t1 = ctree_create_load (cfg, ARG_TYPE (n), t1, &svt, TRUE);
3490 PUSH_TREE (t1, svt);
3499 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3500 t1->data.i = ARG_POS (n);
3501 PUSH_TREE (t1, svt);
3508 token = read32 (ip);
3511 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
3512 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
3513 MonoType *type = mono_type_create_from_typespec (image, token);
3514 t1->data.i = mono_type_size (type, &align);
3515 mono_metadata_free_type (type);
3517 MonoClass *szclass = mono_class_get (image, token);
3518 mono_class_init (szclass);
3519 g_assert (szclass->valuetype);
3520 t1->data.i = mono_class_value_size (szclass, &align);
3523 PUSH_TREE (t1, VAL_I32);
3530 t1 = mono_ctree_new (mp, MB_TERM_CPSRC, sp [1], sp [2]);
3531 t1 = mono_ctree_new (mp, MB_TERM_CPBLK, sp [0], t1);
3532 ADD_TREE (t1, cli_addr);
3535 case CEE_UNALIGNED_: {
3537 /* fixme: implement me */
3540 case CEE_VOLATILE_: {
3542 /* fixme: implement me */
3547 tail_recursion = TRUE;
3549 case CEE_LOCALLOC: {
3553 t1 = mono_ctree_new (mp, MB_TERM_LOCALLOC, *sp, NULL);
3554 t1->data.i = header->init_locals;
3555 PUSH_TREE (t1, VAL_POINTER);
3562 t1 = mono_ctree_new (mp, MB_TERM_CPSRC, sp [1], sp [2]);
3563 t1 = mono_ctree_new (mp, MB_TERM_INITBLK, sp [0], t1);
3564 ADD_TREE (t1, cli_addr);
3568 g_error ("Unimplemented opcode at IL_%04x "
3569 "0xFE %02x", ip - header->code, *ip);
3574 g_warning ("unknown instruction `%s' at IL_%04X",
3575 mono_opcode_names [*ip], ip - header->code);
3576 if (mono_debug_format == MONO_DEBUG_FORMAT_NONE) {
3579 mono_print_forest (cfg, forest);
3580 g_assert_not_reached ();
3584 if ((depth = sp - stack)) {
3585 //printf ("DEPTH %d %d\n", depth, sp [0]->op);
3586 //mono_print_forest (cfg, forest);
3587 create_outstack (cfg, bb, stack, sp - stack);
3591 superblock_end = TRUE;
3594 superblock_end = TRUE;
3595 //printf ("unreached block %d\n", i);
3597 if (repeat_count >= 10) {
3598 /*mono_print_forest (cfg, forest);
3599 g_warning ("repeat count exceeded at ip: 0x%04x in %s\n", bb->cli_addr, cfg->method->name);*/
3603 //printf ("BBE %d %d %d %d\n", i, bb->reached, bb->finished, superblock_end);
3607 //printf ("REPEAT %d\n", repeat);
3608 mono_jit_stats.analyze_stack_repeat++;
3617 mono_cfg_free (MonoFlowGraph *cfg)
3621 for (i = 0; i < cfg->block_count; i++) {
3622 if (!cfg->bblocks [i].reached)
3624 g_ptr_array_free (cfg->bblocks [i].forest, TRUE);
3625 g_list_free (cfg->bblocks [i].succ);
3629 g_free (cfg->bcinfo);
3632 g_free (cfg->bblocks);
3634 g_array_free (cfg->varinfo, TRUE);
3636 mono_mempool_destroy (cfg->mp);
3639 int mono_exc_esp_offset = 0;
3641 static MonoFlowGraph *
3642 mono_cfg_new (MonoMethod *method)
3646 MonoMemPool *mp = mono_mempool_new ();
3648 g_assert (((MonoMethodNormal *)method)->header);
3650 cfg = mono_mempool_alloc0 (mp, sizeof (MonoFlowGraph));
3652 cfg->domain = mono_domain_get ();
3653 cfg->method = method;
3656 /* reserve space to save LMF */
3657 cfg->locals_size = sizeof (MonoLMF);
3659 cfg->locals_size += sizeof (gpointer);
3660 mono_exc_esp_offset = - cfg->locals_size;
3662 cfg->locals_size += sizeof (gpointer);
3664 /* aligment check */
3665 g_assert (!(cfg->locals_size & 0x7));
3667 /* fixme: we should also consider loader optimisation attributes */
3668 cfg->share_code = mono_jit_share_code;
3670 cfg->varinfo = g_array_new (FALSE, TRUE, sizeof (MonoVarInfo));
3672 SET_VARINFO (vi, 0, 0, 0, 0);
3673 g_array_append_val (cfg->varinfo, vi); /* add invalid value at position 0 */
3675 cfg->intvars = mono_mempool_alloc0 (mp, sizeof (guint16) * VAL_DOUBLE *
3676 ((MonoMethodNormal *)method)->header->max_stack);
3678 mono_analyze_flow (cfg);
3680 if (!mono_analyze_stack (cfg)) {
3681 mono_cfg_free (cfg);
3689 mono_get_runtime_method (MonoMethod* method)
3692 const char *name = method->name;
3694 if (method->klass->parent == mono_defaults.multicastdelegate_class) {
3695 if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
3696 return (gpointer)mono_delegate_ctor;
3697 } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
3698 nm = mono_marshal_get_delegate_invoke (method);
3699 return mono_compile_method (nm);
3700 } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
3701 nm = mono_marshal_get_delegate_begin_invoke (method);
3702 return mono_compile_method (nm);
3703 } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
3704 nm = mono_marshal_get_delegate_end_invoke (method);
3705 return mono_compile_method (nm);
3711 #ifdef MONO_USE_EXC_TABLES
3713 mono_type_blittable (MonoType *type)
3718 switch (type->type){
3719 case MONO_TYPE_VOID:
3733 case MONO_TYPE_VALUETYPE:
3734 case MONO_TYPE_CLASS:
3735 return type->data.klass->blittable;
3745 mono_method_blittable (MonoMethod *method)
3747 MonoMethodSignature *sig;
3753 if (!mono_has_unwind_info (method)) {
3757 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
3760 sig = method->signature;
3762 if (!mono_type_blittable (sig->ret))
3765 for (i = 0; i < sig->param_count; i++)
3766 if (!mono_type_blittable (sig->params [i]))
3774 * mono_jit_compile_method:
3775 * @method: pointer to the method info
3777 * JIT compilation of a single method.
3779 * Returns: a pointer to the newly created code.
3782 mono_jit_compile_method (MonoMethod *method)
3784 MonoDomain *target_domain, *domain = mono_domain_get ();
3787 GHashTable *jit_code_hash;
3789 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
3790 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
3792 if (!method->info) {
3795 if (!method->addr && (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
3796 mono_lookup_pinvoke_call (method);
3797 #ifdef MONO_USE_EXC_TABLES
3798 if (mono_method_blittable (method)) {
3799 method->info = method->addr;
3802 nm = mono_marshal_get_native_wrapper (method);
3803 method->info = mono_compile_method (nm);
3804 #ifdef MONO_USE_EXC_TABLES
3808 return method->info;
3811 if (mono_jit_share_code)
3812 target_domain = mono_root_domain;
3814 target_domain = domain;
3816 jit_code_hash = target_domain->jit_code_hash;
3818 if ((addr = g_hash_table_lookup (jit_code_hash, method))) {
3819 mono_jit_stats.methods_lookups++;
3824 mono_jit_stats.methods_compiled++;
3826 if (mono_jit_trace_calls || mono_jit_dump_asm || mono_jit_dump_forest) {
3827 printf ("Start JIT compilation of %s, domain '%s'\n",
3828 mono_method_full_name (method, TRUE), target_domain->friendly_name);
3831 if (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
3832 if (!(addr = mono_get_runtime_method (method))) {
3833 mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
3834 if (mono_debug_format != MONO_DEBUG_FORMAT_NONE)
3837 g_error ("Don't know how to exec runtime method %s", mono_method_full_name (method, TRUE));
3840 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
3842 gulong code_size_ratio;
3844 mono_profiler_method_jit (method);
3846 if (!(cfg = mono_cfg_new (method))) {
3847 mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
3851 cfg->code_size = MAX (header->code_size * 5, 256);
3852 cfg->start = cfg->code = g_malloc (cfg->code_size);
3854 if (mono_method_has_breakpoint (method, FALSE))
3855 x86_breakpoint (cfg->code);
3856 else if (mono_debug_format != MONO_DEBUG_FORMAT_NONE)
3857 x86_nop (cfg->code);
3859 if (!(ji = arch_jit_compile_cfg (target_domain, cfg))) {
3860 mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
3866 mono_jit_stats.allocated_code_size += cfg->code_size;
3868 code_size_ratio = cfg->code - cfg->start;
3869 if (code_size_ratio > mono_jit_stats.biggest_method_size) {
3870 mono_jit_stats.biggest_method_size = code_size_ratio;
3871 mono_jit_stats.biggest_method = method;
3873 code_size_ratio = (code_size_ratio * 100) / header->code_size;
3874 if (code_size_ratio > mono_jit_stats.max_code_size_ratio) {
3875 mono_jit_stats.max_code_size_ratio = code_size_ratio;
3876 mono_jit_stats.max_ratio_method = method;
3880 if (mono_jit_dump_asm) {
3881 char *id = g_strdup_printf ("%s.%s_%s", method->klass->name_space,
3882 method->klass->name, method->name);
3883 mono_disassemble_code (cfg->start, cfg->code - cfg->start, id);
3886 if (mono_debug_format != MONO_DEBUG_FORMAT_NONE)
3887 mono_debug_add_method (cfg);
3890 mono_jit_stats.native_code_size += ji->code_size;
3892 ji->num_clauses = header->num_clauses;
3894 if (header->num_clauses) {
3895 int i, start_block, end_block, filter_block;
3897 ji->clauses = mono_mempool_alloc0 (target_domain->mp,
3898 sizeof (MonoJitExceptionInfo) * header->num_clauses);
3900 for (i = 0; i < header->num_clauses; i++) {
3901 MonoExceptionClause *ec = &header->clauses [i];
3902 MonoJitExceptionInfo *ei = &ji->clauses [i];
3904 ei->flags = ec->flags;
3906 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
3907 g_assert (cfg->bcinfo [ec->token_or_filter].is_block_start);
3908 filter_block = cfg->bcinfo [ec->token_or_filter].block_id;
3909 ei->data.filter = cfg->start + cfg->bblocks [filter_block].addr;
3911 ei->data.token = ec->token_or_filter;
3914 g_assert (cfg->bcinfo [ec->try_offset].is_block_start);
3915 start_block = cfg->bcinfo [ec->try_offset].block_id;
3916 end_block = cfg->bcinfo [ec->try_offset + ec->try_len].block_id;
3917 g_assert (cfg->bcinfo [ec->try_offset + ec->try_len].is_block_start);
3919 ei->try_start = cfg->start + cfg->bblocks [start_block].addr;
3920 ei->try_end = cfg->start + cfg->bblocks [end_block].addr;
3922 g_assert (cfg->bcinfo [ec->handler_offset].is_block_start);
3923 start_block = cfg->bcinfo [ec->handler_offset].block_id;
3924 ei->handler_start = cfg->start + cfg->bblocks [start_block].addr;
3928 mono_jit_info_table_add (target_domain, ji);
3930 mono_regset_free (cfg->rs);
3932 mono_cfg_free (cfg);
3934 mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
3937 if (mono_jit_trace_calls || mono_jit_dump_asm || mono_jit_dump_forest) {
3938 printf ("END JIT compilation of %s %p %p, domain '%s'\n",
3939 mono_method_full_name (method, FALSE),
3942 target_domain->friendly_name);
3945 g_hash_table_insert (jit_code_hash, method, addr);
3947 /* make sure runtime_init is called */
3948 mono_class_vtable (target_domain, method->klass);
3953 /* mono_jit_create_remoting_trampoline:
3954 * @method: pointer to the method info
3956 * Creates a trampoline which calls the remoting functions. This
3957 * is used in the vtable of transparent proxies.
3959 * Returns: a pointer to the newly created code
3962 mono_jit_create_remoting_trampoline (MonoMethod *method)
3965 guint8 *addr = NULL;
3967 nm = mono_marshal_get_remoting_invoke (method);
3968 addr = mono_compile_method (nm);
3973 /* this function is never called */
3975 ves_array_set (MonoArray *this, ...)
3977 g_assert_not_reached ();
3980 /* this function is never called */
3982 ves_array_get (MonoArray *this, ...)
3984 g_assert_not_reached ();
3989 * @assembly: reference to an assembly
3990 * @argc: argument count
3991 * @argv: argument vector
3993 * Start execution of a program.
3996 mono_jit_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
3998 MonoImage *image = assembly->image;
4001 method = mono_get_method (image, mono_image_get_entry_point (image), NULL);
4003 return mono_runtime_run_main (method, argc, argv, NULL);
4006 #ifdef PLATFORM_WIN32
4007 #define GET_CONTEXT \
4008 struct sigcontext *ctx = (struct sigcontext*)_dummy;
4010 #define GET_CONTEXT \
4011 void **_p = (void **)&_dummy; \
4012 struct sigcontext *ctx = (struct sigcontext *)++_p;
4016 sigfpe_signal_handler (int _dummy)
4021 exc = mono_get_exception_divide_by_zero ();
4023 arch_handle_exception (ctx, exc, FALSE);
4027 sigill_signal_handler (int _dummy)
4031 exc = mono_get_exception_execution_engine ("SIGILL");
4033 arch_handle_exception (ctx, exc, FALSE);
4037 sigsegv_signal_handler (int _dummy)
4042 exc = mono_get_exception_null_reference ();
4044 arch_handle_exception (ctx, exc, FALSE);
4048 sigusr1_signal_handler (int _dummy)
4053 thread = mono_thread_current ();
4055 g_assert (thread->abort_exc);
4057 arch_handle_exception (ctx, thread->abort_exc, FALSE);
4061 mono_get_lmf_addr (void)
4063 MonoJitTlsData *jit_tls;
4065 if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
4066 return &jit_tls->lmf;
4068 g_assert_not_reached ();
4073 * mono_thread_abort:
4074 * @obj: exception object
4076 * abort the thread, print exception information and stack trace
4079 mono_thread_abort (MonoObject *obj)
4081 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
4089 mono_thread_start_cb (guint32 tid, gpointer stack_start, gpointer func)
4091 MonoJitTlsData *jit_tls;
4094 jit_tls = g_new0 (MonoJitTlsData, 1);
4096 TlsSetValue (mono_jit_tls_id, jit_tls);
4098 jit_tls->abort_func = mono_thread_abort;
4099 jit_tls->end_of_stack = stack_start;
4101 lmf = g_new0 (MonoLMF, 1);
4106 mono_debugger_event (MONO_DEBUGGER_EVENT_THREAD_CREATED, (gpointer)tid, func);
4109 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
4112 mono_thread_abort_dummy (MonoObject *obj)
4114 if (mono_thread_attach_aborted_cb)
4115 mono_thread_attach_aborted_cb (obj);
4117 mono_thread_abort (obj);
4121 mono_thread_attach_cb (guint32 tid, gpointer stack_start)
4123 MonoJitTlsData *jit_tls;
4126 jit_tls = g_new0 (MonoJitTlsData, 1);
4128 TlsSetValue (mono_jit_tls_id, jit_tls);
4130 jit_tls->abort_func = mono_thread_abort_dummy;
4131 jit_tls->end_of_stack = stack_start;
4133 lmf = g_new0 (MonoLMF, 1);
4139 static CRITICAL_SECTION ms;
4142 mono_runtime_install_handlers (void)
4144 #ifndef PLATFORM_WIN32
4145 struct sigaction sa;
4148 #ifdef PLATFORM_WIN32
4150 win32_seh_set_handler(SIGFPE, sigfpe_signal_handler);
4151 win32_seh_set_handler(SIGILL, sigill_signal_handler);
4152 win32_seh_set_handler(SIGSEGV, sigsegv_signal_handler);
4153 #else /* !PLATFORM_WIN32 */
4155 /* libpthreads has its own implementation of sigaction(),
4156 * but it seems to work well with our current exception
4157 * handlers. If not we must call syscall directly instead
4161 sa.sa_handler = sigfpe_signal_handler;
4162 sigemptyset (&sa.sa_mask);
4164 //g_assert (syscall (SYS_sigaction, SIGFPE, &sa, NULL) != -1);
4165 g_assert (sigaction (SIGFPE, &sa, NULL) != -1);
4168 sa.sa_handler = sigill_signal_handler;
4169 sigemptyset (&sa.sa_mask);
4171 //g_assert (syscall (SYS_sigaction, SIGILL, &sa, NULL) != -1);
4172 g_assert (sigaction (SIGILL, &sa, NULL) != -1);
4174 /* catch the thread abort signal */
4175 sa.sa_handler = sigusr1_signal_handler;
4176 sigemptyset (&sa.sa_mask);
4178 //g_assert (syscall (SYS_sigaction, SIGILL, &sa, NULL) != -1);
4179 g_assert (syscall (SYS_sigaction, mono_thread_get_abort_signal (), &sa, NULL) != -1);
4180 //g_assert (sigaction (mono_thread_get_abort_signal (), &sa, NULL) != -1);
4184 sa.sa_handler = sigsegv_signal_handler;
4185 sigemptyset (&sa.sa_mask);
4187 //g_assert (syscall (SYS_sigaction, SIGSEGV, &sa, NULL) != -1);
4188 g_assert (sigaction (SIGSEGV, &sa, NULL) != -1);
4190 #endif /* PLATFORM_WIN32 */
4194 mono_jit_init (const char *file) {
4199 mono_runtime_install_handlers ();
4202 mono_add_internal_call ("System.Array::Set", ves_array_set);
4203 mono_add_internal_call ("System.Array::Get", ves_array_get);
4204 mono_add_internal_call ("System.Array::Address", ves_array_element_address);
4205 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
4206 ves_icall_get_frame_info);
4207 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",
4208 ves_icall_get_trace);
4209 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers", mono_runtime_install_handlers);
4211 metadata_section = &ms;
4212 InitializeCriticalSection (metadata_section);
4214 mono_jit_tls_id = TlsAlloc ();
4216 /* Don't set up the main thread for managed code execution -
4217 * this will give a handy assertion fail in
4218 * mono_get_lmf_addr() if any buggy runtime code tries to run
4219 * managed code in this thread.
4221 /* mono_thread_start_cb (GetCurrentThreadId (), (gpointer)-1, NULL); */
4223 mono_install_compile_method (mono_jit_compile_method);
4224 mono_install_trampoline (arch_create_jit_trampoline);
4225 mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline);
4226 mono_install_handler (arch_get_throw_exception ());
4227 mono_install_runtime_invoke (mono_jit_runtime_invoke);
4228 mono_install_stack_walk (mono_jit_walk_stack);
4229 mono_install_get_config_dir ();
4231 domain = mono_init (file);
4232 mono_runtime_init (domain, mono_thread_start_cb, mono_thread_attach_cb);
4238 mono_jit_cleanup (MonoDomain *domain)
4240 mono_runtime_cleanup (domain);
4242 mono_domain_finalize (domain);
4244 mono_debug_cleanup ();
4246 #ifdef PLATFORM_WIN32
4247 win32_seh_cleanup();
4250 mono_domain_unload (domain, TRUE);
4252 if (mono_jit_stats.enabled) {
4253 g_print ("Mono Jit statistics\n");
4254 g_print ("Compiled methods: %ld\n", mono_jit_stats.methods_compiled);
4255 g_print ("Methods cache lookup: %ld\n", mono_jit_stats.methods_lookups);
4256 g_print ("Method trampolines: %ld\n", mono_jit_stats.method_trampolines);
4257 g_print ("Basic blocks: %ld\n", mono_jit_stats.basic_blocks);
4258 g_print ("Max basic blocks: %ld\n", mono_jit_stats.max_basic_blocks);
4259 g_print ("Allocated vars: %ld\n", mono_jit_stats.allocate_var);
4260 g_print ("Analyze stack repeat: %ld\n", mono_jit_stats.analyze_stack_repeat);
4261 g_print ("Compiled CIL code size: %ld\n", mono_jit_stats.cil_code_size);
4262 g_print ("Native code size: %ld\n", mono_jit_stats.native_code_size);
4263 g_print ("Max code size ratio: %.2f (%s::%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
4264 mono_jit_stats.max_ratio_method->klass->name, mono_jit_stats.max_ratio_method->name);
4265 g_print ("Biggest method: %ld (%s::%s)\n", mono_jit_stats.biggest_method_size,
4266 mono_jit_stats.biggest_method->klass->name, mono_jit_stats.biggest_method->name);
4267 g_print ("Code reallocs: %ld\n", mono_jit_stats.code_reallocs);
4268 g_print ("Allocated code size: %ld\n", mono_jit_stats.allocated_code_size);
4269 g_print ("Inlineable methods: %ld\n", mono_jit_stats.inlineable_methods);
4270 g_print ("Inlined methods: %ld\n", mono_jit_stats.inlined_methods);
4272 g_print ("\nCreated object count: %ld\n", mono_stats.new_object_count);
4273 g_print ("Initialized classes: %ld\n", mono_stats.initialized_class_count);
4274 g_print ("Used classes: %ld\n", mono_stats.used_class_count);
4275 g_print ("Static data size: %ld\n", mono_stats.class_static_data_size);
4276 g_print ("VTable data size: %ld\n", mono_stats.class_vtable_size);
4279 DeleteCriticalSection (metadata_section);
4285 * @image: reference to an image
4286 * @verbose: If true, print debugging information on stdout.
4288 * JIT compilation of all methods in the image.
4291 mono_jit_compile_image (MonoImage *image, int verbose)
4294 MonoTableInfo *t = &image->tables [MONO_TABLE_METHOD];
4297 for (i = 0; i < t->rows; i++) {
4299 method = mono_get_method (image,
4300 (MONO_TABLE_METHOD << 24) | (i + 1),
4304 g_print ("Compiling: %s:%s\n\n", image->assembly_name, method->name);
4306 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT) {
4308 printf ("ABSTARCT\n");
4310 mono_compile_method (method);