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>
35 #include <mono/metadata/mono-debug.h>
36 #include <mono/metadata/mono-debug-debugger.h>
42 #include "debug-jit.h"
45 * if OPT_BOOL is defined we use 32bit to store boolean local variables. This
46 * gives great speedup for boolean expressions, but unfortunately it changes
47 * semantics, so i disable it until we have a real solution */
48 /* #define OPT_BOOL */
50 #define MAKE_CJUMP(name) \
52 case CEE_##name##_S: { \
54 int near_jump = *ip == CEE_##name##_S; \
57 t1 = mono_ctree_new (mp, MB_TERM_COMPARE, sp [0], sp [1]); \
58 t1 = mono_ctree_new (mp, MB_TERM_CBRANCH, t1, NULL); \
60 target = cli_addr + 2 + (signed char) *ip; \
62 target = cli_addr + 5 + (gint32) read32 (ip); \
63 g_assert (target >= 0 && target <= header->code_size); \
64 g_assert (bcinfo [target].is_block_start); \
65 tbb = &cfg->bblocks [bcinfo [target].block_id]; \
66 create_outstack (cfg, bb, stack, sp - stack); \
67 mark_reached (cfg, tbb, bb->outstack, bb->outdepth); \
68 t1->data.bi.target = tbb; \
69 t1->data.bi.cond = CEE_##name; \
70 ADD_TREE (t1, cli_addr); \
71 ip += near_jump ? 1: 4; \
75 #define MAKE_BI_ALU(name) \
79 t1 = mono_ctree_new (mp, MB_TERM_##name, sp [0], sp [1]); \
80 PUSH_TREE (t1, sp [0]->svt); \
85 #define MAKE_SPILLED_BI_ALU1(name, s1, s2) { \
86 t1 = mono_ctree_new (mp, MB_TERM_##name, s1, s2); \
87 PUSH_TREE (t1, s1->svt); }
89 #define MAKE_SPILLED_BI_ALU1(name, s1, s2) \
90 t1 = mono_ctree_new (mp, MB_TERM_##name, s1, s2); \
92 t1 = mono_store_tree (cfg, -1, t1, &t2); \
94 ADD_TREE (t1, cli_addr); \
95 PUSH_TREE (t2, t2->svt);
98 #define MAKE_CMP(cname) \
102 t1 = mono_ctree_new (mp, MB_TERM_COMPARE, sp [0], sp [1]); \
103 t1 = mono_ctree_new (mp, MB_TERM_CSET, t1, NULL); \
104 t1->data.i = CEE_##cname; \
105 PUSH_TREE (t1, VAL_I32); \
109 #define MAKE_SPILLED_BI_ALU(name) \
113 MAKE_SPILLED_BI_ALU1 (name, sp [0], sp [1]) \
117 #define MAKE_LDIND(name, op, svt) \
121 t1 = mono_ctree_new (mp, op, *sp, NULL); \
122 PUSH_TREE (t1, svt); \
126 #define MAKE_LDELEM(name, op, svt, s) \
130 t1 = mono_ctree_new (mp, MB_TERM_LDELEMA, sp [0], sp [1]); \
132 t1 = mono_ctree_new (mp, op, t1, NULL); \
133 PUSH_TREE (t1, svt); \
137 #define MAKE_LDELEM_OLD(name, op, svt, s) \
141 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4); \
143 t1 = mono_ctree_new (mp, MB_TERM_MUL, sp [1], t1); \
144 t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4); \
145 t2->data.i = G_STRUCT_OFFSET (MonoArray, vector); \
146 t2 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], t2); \
147 t1 = mono_ctree_new (mp, MB_TERM_ADD, t1, t2); \
148 t1 = mono_ctree_new (mp, op, t1, NULL); \
149 PUSH_TREE (t1, svt); \
153 #define MAKE_STIND(name, op) \
157 t1 = mono_ctree_new (mp, op, sp [0], sp [1]); \
158 ADD_TREE (t1, cli_addr); \
162 #define MAKE_STELEM(name, op, s) \
166 t1 = mono_ctree_new (mp, MB_TERM_LDELEMA, sp [0], sp [1]); \
168 t1 = mono_ctree_new (mp, op, t1, sp [2]); \
169 ADD_TREE (t1, cli_addr); \
173 #define MAKE_STELEM_OLD(name, op, s) \
177 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4); \
179 t1 = mono_ctree_new (mp, MB_TERM_MUL, sp [1], t1); \
180 t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4); \
181 t2->data.i = G_STRUCT_OFFSET (MonoArray, vector); \
182 t2 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], t2); \
183 t1 = mono_ctree_new (mp, MB_TERM_ADD, t1, t2); \
184 t1 = mono_ctree_new (mp, op, t1, sp [2]); \
185 ADD_TREE (t1, cli_addr); \
192 const unsigned char *end, *saved_ip;
193 MonoImage *saved_image;
196 /* Whether to dump the assembly code after genreating it */
197 gboolean mono_jit_dump_asm = FALSE;
199 /* Whether to dump the forest */
200 gboolean mono_jit_dump_forest = FALSE;
202 /* Whether to print function call traces */
203 gboolean mono_jit_trace_calls = FALSE;
205 /* Whether to insert in the code profile callbacks */
206 gboolean mono_jit_profile = FALSE;
208 /* Force jit to share code between application domains */
209 gboolean mono_jit_share_code = FALSE;
211 /* use linear scan register allocation */
212 gboolean mono_use_linear_scan = TRUE;
215 gboolean mono_jit_inline_code = TRUE;
217 /* generate bound checking */
218 gboolean mono_jit_boundcheck = TRUE;
221 gboolean mono_inline_memcpy = TRUE;
223 /* Use alternative (faster) sequence to convert FP values to integers */
224 gboolean mono_use_fast_iconv = FALSE;
226 /* TLS id to store jit data */
227 guint32 mono_jit_tls_id;
229 /* issue a breakpoint on unhandled excepions */
230 gboolean mono_break_on_exc = FALSE;
232 MonoJitStats mono_jit_stats;
235 * We sometimes need static data, for example the forest generator need it to
236 * store constants or class data.
238 inline static gpointer
239 mono_alloc_static (int size)
241 return g_malloc (size);
243 inline static gpointer
244 mono_alloc_static0 (int size)
246 return g_malloc0 (size);
249 typedef void (*MonoCCtor) (void);
252 mono_allocate_intvar (MonoFlowGraph *cfg, int slot, MonoValueType type)
254 int size, align, vnum, pos;
256 g_assert (type != VAL_UNKNOWN);
258 /* take care if you modify MonoValueType */
259 g_assert (VAL_DOUBLE == 4);
261 /* fixme: machine dependant */
262 if (type == VAL_POINTER)
263 type = VAL_I32; /* VAL_I32 and VAL_POINTER share the same slot */
265 pos = type - 1 + slot * VAL_DOUBLE;
267 if ((vnum = cfg->intvars [pos]))
269 mono_get_val_sizes (type, &size, &align);
271 cfg->intvars[pos] = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, type);
273 return cfg->intvars[pos];
277 mono_allocate_excvar (MonoFlowGraph *cfg)
282 cfg->excvar = arch_allocate_var (cfg, 4, 4, MONO_TEMPVAR, VAL_POINTER);
284 VARINFO (cfg, cfg->excvar).isvolatile = 1;
290 * mono_jit_runtime_invoke:
291 * @method: the method to invoke
293 * @params: array of parameter values.
294 * @exc: used to catch exceptions objects
297 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
300 MonoObject *(*runtime_invoke) (MonoObject *this, void **params, MonoObject **exc);
302 invoke = mono_marshal_get_runtime_invoke (method);
303 runtime_invoke = mono_compile_method (invoke);
304 return runtime_invoke (obj, params, exc);
309 * @cfg: pointer to the control flow graph
310 * @type: the type of the value to load
311 * @addr: the address of the value
313 * Creates a tree to load the value at address @addr.
315 inline static MBTree *
316 ctree_create_load (MonoFlowGraph *cfg, MonoType *type, MBTree *addr, MonoValueType *svt, gboolean arg)
318 MonoMemPool *mp = cfg->mp;
323 ldind = mono_map_ldarg_type (type, svt);
325 ldind = mono_map_ldind_type (type, svt);
327 t = mono_ctree_new (mp, ldind, addr, NULL);
333 * ctree_create_store:
334 * @mp: pointer to a memory pool
335 * @s: the value (tree) to store
336 * @type: the type of the value
337 * @addr: the address of the value
339 * Creates a tree to store the value @s at address @addr.
341 inline static MBTree *
342 ctree_create_store (MonoFlowGraph *cfg, MonoType *type, MBTree *addr,
343 MBTree *s, gboolean arg)
345 MonoMemPool *mp = cfg->mp;
350 stind = mono_map_starg_type (type);
352 stind = mono_map_stind_type (type);
354 t = mono_ctree_new (mp, stind, addr, s);
356 if (MONO_TYPE_ISSTRUCT (type))
357 t->data.i = mono_class_value_size (type->data.klass, NULL);
362 inline static MBTree *
363 ctree_dup_address (MonoMemPool *mp, MBTree *s)
371 t = mono_ctree_new_leaf (mp, s->op);
372 t->data.i = s->data.i;
373 t->svt = VAL_POINTER;
376 g_warning ("unknown tree opcode %d", s->op);
377 g_assert_not_reached ();
384 * Create a duplicate of the value of a tree. This is
385 * easy for trees starting with LDIND/STIND, since the
386 * duplicate is simple a LDIND tree with the same address.
387 * For other trees we have to split the tree into one tree
388 * storing the value to a new temporary variable, and
389 * another tree which loads that value back. We can then
390 * duplicate the second tree.
393 ctree_create_dup (MonoMemPool *mp, MBTree *s)
398 case MB_TERM_STIND_I1:
399 case MB_TERM_LDIND_I1:
400 t = ctree_dup_address (mp, s->left);
401 t = mono_ctree_new (mp, MB_TERM_LDIND_I1, t, NULL);
404 case MB_TERM_STIND_I2:
405 case MB_TERM_LDIND_I2:
406 t = ctree_dup_address (mp, s->left);
407 t = mono_ctree_new (mp, MB_TERM_LDIND_I2, t, NULL);
410 case MB_TERM_STIND_I4:
411 case MB_TERM_LDIND_I4:
412 t = ctree_dup_address (mp, s->left);
413 t = mono_ctree_new (mp, MB_TERM_LDIND_I4, t, NULL);
416 case MB_TERM_STIND_I8:
417 case MB_TERM_LDIND_I8:
418 t = ctree_dup_address (mp, s->left);
419 t = mono_ctree_new (mp, MB_TERM_LDIND_I8, t, NULL);
422 case MB_TERM_STIND_R4:
423 case MB_TERM_LDIND_R4:
424 t = ctree_dup_address (mp, s->left);
425 t = mono_ctree_new (mp, MB_TERM_LDIND_R4, t, NULL);
428 case MB_TERM_STIND_R8:
429 case MB_TERM_LDIND_R8:
430 t = ctree_dup_address (mp, s->left);
431 t = mono_ctree_new (mp, MB_TERM_LDIND_R8, t, NULL);
434 case MB_TERM_STIND_OBJ:
435 case MB_TERM_LDIND_OBJ:
436 t = ctree_dup_address (mp, s->left);
437 t = mono_ctree_new (mp, MB_TERM_LDIND_OBJ, t, NULL);
438 t->svt = VAL_UNKNOWN;
441 g_warning ("unknown op \"%s\"", mono_burg_term_string [s->op]);
442 g_assert_not_reached ();
449 mono_store_tree (MonoFlowGraph *cfg, int slot, MBTree *s, MBTree **tdup)
451 MonoMemPool *mp = cfg->mp;
456 case MB_TERM_STIND_I1:
457 case MB_TERM_LDIND_I1:
458 case MB_TERM_STIND_I2:
459 case MB_TERM_LDIND_I2:
460 case MB_TERM_STIND_I4:
461 case MB_TERM_LDIND_I4:
462 case MB_TERM_STIND_I8:
463 case MB_TERM_LDIND_I8:
464 case MB_TERM_STIND_R4:
465 case MB_TERM_LDIND_R4:
466 case MB_TERM_STIND_R8:
467 case MB_TERM_LDIND_R8: {
469 vnum = mono_allocate_intvar (cfg, slot, s->svt);
471 if (s->left->op == MB_TERM_ADDR_L && s->left->data.i == vnum) {
473 *tdup = ctree_create_dup (mp, s);
479 *tdup = ctree_create_dup (mp, s);
484 g_assert (s->svt != VAL_UNKNOWN);
488 vnum = mono_allocate_intvar (cfg, slot, s->svt);
491 mono_get_val_sizes (s->svt, &size, &align);
492 vnum = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, s->svt);
495 t = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
498 t = mono_ctree_new (mp, mono_map_store_svt_type (s->svt), t, s);
504 *tdup = ctree_create_dup (mp, t);
510 mono_find_final_block (MonoFlowGraph *cfg, guint32 ip, guint32 target, int type)
512 MonoMethod *method = cfg->method;
513 MonoBytecodeInfo *bcinfo = cfg->bcinfo;
514 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
515 MonoExceptionClause *clause;
518 for (i = 0; i < header->num_clauses; ++i) {
519 clause = &header->clauses [i];
521 if (MONO_OFFSET_IN_CLAUSE (clause, ip) &&
522 (!MONO_OFFSET_IN_CLAUSE (clause, target))) {
523 if (clause->flags & type) {
524 g_assert (bcinfo [clause->handler_offset].is_block_start);
525 return &cfg->bblocks [bcinfo [clause->handler_offset].block_id];
533 mono_cfg_add_successor (MonoFlowGraph *cfg, MonoBBlock *bb, gint32 target)
538 g_assert (cfg->bcinfo [target].is_block_start);
540 tbb = &cfg->bblocks [cfg->bcinfo [target].block_id];
543 for (l = bb->succ; l; l = l->next) {
544 MonoBBlock *t = (MonoBBlock *)l->data;
549 bb->succ = g_list_prepend (bb->succ, tbb);
553 #define CREATE_BLOCK(t) {if (!bcinfo [t].is_block_start) {block_count++;bcinfo [t].is_block_start = 1; }}
556 mono_analyze_flow (MonoFlowGraph *cfg)
558 MonoMethod *method = cfg->method;
559 const unsigned char *ip, *end;
560 MonoMethodHeader *header;
561 MonoBytecodeInfo *bcinfo;
562 MonoExceptionClause *clause;
563 MonoBBlock *bblocks, *bb;
564 const MonoOpcode *opcode;
568 header = ((MonoMethodNormal *)method)->header;
570 bcinfo = g_malloc0 (header->code_size * sizeof (MonoBytecodeInfo));
571 bcinfo [0].is_block_start = 1;
576 end = ip + header->code_size;
578 mono_jit_stats.cil_code_size += header->code_size;
580 for (i = 0; i < header->num_clauses; ++i) {
581 clause = &header->clauses [i];
583 CREATE_BLOCK (clause->try_offset);
584 CREATE_BLOCK (clause->handler_offset);
586 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER)
587 CREATE_BLOCK (clause->token_or_filter);
591 guint32 cli_addr = ip - header->code;
593 //printf ("IL%04x OPCODE %s\n", cli_addr, mono_opcode_names [*ip]);
596 CREATE_BLOCK (cli_addr);
600 i = mono_opcode_value (&ip);
602 opcode = &mono_opcodes [i];
604 switch (opcode->flow_type) {
605 case MONO_FLOW_RETURN:
606 case MONO_FLOW_ERROR:
609 case MONO_FLOW_BRANCH: /* we handle branch when checking the argument type */
610 case MONO_FLOW_COND_BRANCH:
616 g_assert_not_reached ();
619 switch (opcode->argument) {
623 case MonoInlineString:
624 mono_ldstr (mono_domain_get (), method->klass->image, mono_metadata_token_index (read32 (ip + 1)));
627 case MonoInlineField:
628 case MonoInlineMethod:
631 case MonoShortInlineR:
638 case MonoShortInlineVar:
639 case MonoShortInlineI:
642 case MonoShortInlineBrTarget:
644 i = (signed char)*ip;
646 CREATE_BLOCK (cli_addr + 2 + i);
650 case MonoInlineBrTarget:
654 CREATE_BLOCK (cli_addr + 5 + i);
657 case MonoInlineSwitch: {
658 gint32 st, target, n;
662 st = cli_addr + 5 + 4 * n;
665 for (i = 0; i < n; i++) {
666 target = read32 (ip) + st;
668 CREATE_BLOCK (target);
671 * Note: the code didn't set block_end in switch.
680 g_assert_not_reached ();
685 g_assert (block_count);
687 bb = bblocks = g_malloc0 (sizeof (MonoBBlock) * block_count);
690 bblocks [0].reached = 1;
692 for (i = 0; i < header->code_size; i++) {
693 if (bcinfo [i].is_block_start) {
695 bb->num = block_count;
696 bb->forest = g_ptr_array_new ();
698 bb [-1].length = i - bb [-1].cli_addr;
699 bcinfo [i].block_id = block_count;
704 bb [-1].length = header->code_size - bb [-1].cli_addr;
706 cfg->bcinfo = bcinfo;
707 cfg->bblocks = bblocks;
708 cfg->block_count = block_count;
710 mono_jit_stats.basic_blocks += block_count;
711 mono_jit_stats.max_basic_blocks = MAX (block_count, mono_jit_stats.max_basic_blocks);
713 for (i = 0; i < header->num_clauses; ++i) {
714 MonoBBlock *sbb, *tbb;
715 clause = &header->clauses [i];
716 sbb = &cfg->bblocks [bcinfo [clause->try_offset].block_id];
717 tbb = &cfg->bblocks [bcinfo [clause->handler_offset].block_id];
718 g_assert (sbb && tbb);
719 sbb->succ = g_list_prepend (sbb->succ, tbb);
723 end = ip + header->code_size;
727 guint32 cli_addr = ip - header->code;
729 if (bcinfo [cli_addr].is_block_start) {
730 MonoBBlock *tbb = &cfg->bblocks [bcinfo [cli_addr].block_id];
732 bb->succ = g_list_prepend (bb->succ, tbb);
737 i = mono_opcode_value (&ip);
739 opcode = &mono_opcodes [i];
741 switch (opcode->argument) {
745 case MonoInlineString:
747 case MonoInlineField:
748 case MonoInlineMethod:
751 case MonoShortInlineR:
758 case MonoShortInlineVar:
759 case MonoShortInlineI:
762 case MonoShortInlineBrTarget:
764 i = (signed char)*ip;
766 mono_cfg_add_successor (cfg, bb, cli_addr + 2 + i);
767 if (opcode->flow_type == MONO_FLOW_COND_BRANCH)
768 mono_cfg_add_successor (cfg, bb, cli_addr + 2);
770 case MonoInlineBrTarget:
774 mono_cfg_add_successor (cfg, bb, cli_addr + 5 + i);
775 if (opcode->flow_type == MONO_FLOW_COND_BRANCH)
776 mono_cfg_add_successor (cfg, bb, cli_addr + 5);
778 case MonoInlineSwitch: {
779 gint32 st, target, n;
783 st = cli_addr + 5 + 4 * n;
784 mono_cfg_add_successor (cfg, bb, st);
786 for (i = 0; i < n; i++) {
787 target = read32 (ip) + st;
789 mono_cfg_add_successor (cfg, bb, target);
798 g_assert_not_reached ();
804 * ves_array_element_address:
805 * @this: a pointer to the array object
807 * Returns: the address of an array element.
810 ves_array_element_address (MonoArray *this, ...)
819 g_assert (this != NULL);
823 class = this->obj.vtable->klass;
825 ind = va_arg(ap, int);
826 g_assert (this->bounds != NULL);
828 ind -= this->bounds [0].lower_bound;
829 for (i = 1; i < class->rank; i++) {
830 ind = ind*this->bounds [i].length + va_arg(ap, int) -
831 this->bounds [i].lower_bound;;
834 if (ind >= this->max_length)
835 mono_raise_exception (mono_get_exception_index_out_of_range ());
837 esize = mono_array_element_size (class);
838 ea = (gpointer*)((char*)this->vector + (ind * esize));
839 //printf ("AADDRESS %p %p %d %d %08X\n", this, ea, ind, esize, *(gpointer *)ea);
847 mono_array_new_va (MonoMethod *cm, ...)
849 MonoDomain *domain = mono_domain_get ();
852 guint32 *lower_bounds;
853 int pcount = cm->signature->param_count;
854 int rank = cm->klass->rank;
859 lengths = alloca (sizeof (guint32) * pcount);
860 for (i = 0; i < pcount; ++i)
861 lengths [i] = d = va_arg(ap, int);
863 if (rank == pcount) {
864 /* Only lengths provided. */
867 g_assert (pcount == (rank * 2));
868 /* lower bounds are first. */
869 lower_bounds = lengths;
874 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
877 #define ADD_TREE(t,a) do { t->cli_addr = a; g_ptr_array_add (forest, (t)); } while (0)
878 #define PUSH_TREE(t,k) do { int tt = k; *sp = t; t->svt = tt; t->cli_addr = cli_addr; sp++; } while (0)
880 #define LOCAL_POS(n) (1 + n)
883 #define LOCAL_TYPE(n) ((header)->locals [(n)]->type == MONO_TYPE_BOOLEAN && !(header)->locals [(n)]->byref ? &mono_defaults.int32_class->byval_arg : (header)->locals [(n)])
885 #define LOCAL_TYPE(n) ((header)->locals [(n)])
888 #define ARG_POS(n) (firstarg + n)
889 #define ARG_TYPE(n) ((n) ? (signature)->params [(n) - (signature)->hasthis] : \
890 (signature)->hasthis ? &method->klass->this_arg: (signature)->params [(0)])
894 * replaces all occurences of variable @varnum in @tree with @copy.
897 mono_copy_used_var (MonoFlowGraph *cfg, MBTree *tree, int varnum, MBTree **copy)
903 mono_copy_used_var (cfg, tree->left, varnum, copy);
905 mono_copy_used_var (cfg, tree->right, varnum, copy);
908 case MB_TERM_LDIND_I1:
909 case MB_TERM_LDIND_I2:
910 case MB_TERM_LDIND_I4:
911 case MB_TERM_LDIND_I8:
912 case MB_TERM_LDIND_R4:
913 case MB_TERM_LDIND_R8:
914 if (tree->left->op == MB_TERM_ADDR_L &&
915 tree->left->data.i == varnum) {
917 tree->left->data.i = (*copy)->left->data.i;
921 mono_get_val_sizes (tree->svt, &size, &align);
922 v = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, tree->svt);
924 t1 = mono_ctree_new_leaf (cfg->mp, MB_TERM_ADDR_L);
927 t2 = mono_ctree_new_leaf (cfg->mp, MB_TERM_ADDR_L);
929 t2 = mono_ctree_new (cfg->mp, tree->op, t2, NULL);
931 t2 = mono_ctree_new (cfg->mp, mono_map_store_svt_type (tree->svt), t1, t2);
934 tree->left->data.i = v;
942 * if a variable is modified and there are still referencence
943 * to it on the runtime stack we need to store the value into
944 * a temporary variable and use that value instead of the
948 mono_stack_duplicate_used_var (MonoFlowGraph *cfg, MBTree **stack, MBTree **sp, int varnum)
953 mono_copy_used_var (cfg, *stack, varnum, &res);
961 check_inlining (MonoMethod *method)
963 MonoMethodHeader *header;
964 MonoMethodSignature *signature = method->signature;
965 register const unsigned char *ip, *end;
967 int i, arg_used [256];
971 if (method->inline_info)
972 return method->inline_count;
974 method->inline_info = 1;
976 if (method->wrapper_type != MONO_WRAPPER_NONE)
979 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
980 (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
981 (method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
982 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
983 (method->klass->marshalbyref) ||
984 MONO_TYPE_ISSTRUCT (signature->ret))
987 if (!(header = ((MonoMethodNormal *)method)->header) ||
991 if (header->num_clauses)
995 end = ip + header->code_size;
997 for (i = 0; i < 256; i++)
1001 while (!stop && ip < end) {
1050 case CEE_CONV_OVF_I1_UN:
1051 case CEE_CONV_OVF_I2_UN:
1052 case CEE_CONV_OVF_I4_UN:
1053 case CEE_CONV_OVF_I8_UN:
1054 case CEE_CONV_OVF_U1_UN:
1055 case CEE_CONV_OVF_U2_UN:
1056 case CEE_CONV_OVF_U4_UN:
1057 case CEE_CONV_OVF_U8_UN:
1058 case CEE_CONV_OVF_I_UN:
1059 case CEE_CONV_OVF_U_UN:
1071 case CEE_LDELEM_REF:
1079 case CEE_STELEM_REF:
1080 case CEE_CONV_OVF_I1:
1081 case CEE_CONV_OVF_U1:
1082 case CEE_CONV_OVF_I2:
1083 case CEE_CONV_OVF_U2:
1084 case CEE_CONV_OVF_I4:
1085 case CEE_CONV_OVF_U4:
1086 case CEE_CONV_OVF_I8:
1087 case CEE_CONV_OVF_U8:
1092 case CEE_CONV_OVF_I:
1093 case CEE_CONV_OVF_U:
1095 case CEE_ADD_OVF_UN:
1097 case CEE_MUL_OVF_UN:
1099 case CEE_SUB_OVF_UN:
1145 case CEE_CALLVIRT: {
1149 token = read32 (ip);
1152 if (method->wrapper_type != MONO_WRAPPER_NONE)
1153 cm = mono_method_get_wrapper_data (method, token);
1155 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);
1982 t2->data.nonvirt_info.method = cm;
1984 t2->data.nonvirt_info.p = mono_array_new_va;
1986 t2->data.nonvirt_info.p = arch_create_jit_trampoline (cm);
1989 t1 = mono_ctree_new (mp, MB_TERM_CALL_I4, this, t2);
1990 t1->data.call_info.pad = arg_info [0].pad;
1991 t1->data.call_info.frame_size = frame_size;
1992 t1->svt = VAL_POINTER;
1994 t1 = mono_store_tree (cfg, -1, t1, &t2);
1996 ADD_TREE (t1, cli_addr);
1997 PUSH_TREE (t2, t2->svt);
2001 t2 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
2002 t2->data.nonvirt_info.p = arch_create_jit_trampoline (cm);
2003 t2->data.nonvirt_info.method = cm;
2005 t1 = mono_ctree_new (mp, mono_map_call_type (csig->ret, &svt), this, t2);
2006 t1->data.call_info.pad = arg_info [0].pad;
2007 t1->data.call_info.frame_size = frame_size;
2010 ADD_TREE (t1, cli_addr);
2012 t1 = ctree_create_dup (mp, this);
2014 if (cm->klass->valuetype) {
2015 t2 = ctree_create_load (cfg, &cm->klass->byval_arg, t1, &svt, FALSE);
2016 PUSH_TREE (t2, svt);
2018 PUSH_TREE (t1, t1->svt);
2022 if (csig->param_count > 9)
2029 case CEE_CALLVIRT: {
2030 MonoMethodSignature *csig;
2032 MBTree *ftn, *this = NULL;
2035 int virtual = *ip == CEE_CALLVIRT;
2036 int calli = *ip == CEE_CALLI;
2038 /* fixme: compute this value */
2039 gboolean shared_to_unshared_call = FALSE;
2040 int nargs, vtype_num = 0;
2043 token = read32 (ip);
2046 tail_recursion = FALSE;
2051 if (method->wrapper_type != MONO_WRAPPER_NONE)
2052 csig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
2054 csig = mono_metadata_parse_signature (image, token);
2057 arg_sp = sp -= csig->param_count;
2059 cm = mono_get_method (image, token, NULL);
2062 if (cm->klass == mono_defaults.math_class &&
2063 cm->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
2065 if (!strcmp (cm->name, "Sin")) {
2067 t1 = mono_ctree_new (mp, MB_TERM_SIN, *sp, NULL);
2068 PUSH_TREE (t1, VAL_DOUBLE);
2070 } else if (!strcmp (cm->name, "Cos")) {
2072 t1 = mono_ctree_new (mp, MB_TERM_COS, *sp, NULL);
2073 PUSH_TREE (t1, VAL_DOUBLE);
2075 } else if (!strcmp (cm->name, "Sqrt")) {
2077 t1 = mono_ctree_new (mp, MB_TERM_SQRT, *sp, NULL);
2078 PUSH_TREE (t1, VAL_DOUBLE);
2083 if (cm->string_ctor)
2084 g_assert_not_reached ();
2086 arg_sp = sp -= cm->signature->param_count;
2088 if ((cm->flags & METHOD_ATTRIBUTE_FINAL &&
2089 cm->klass != mono_defaults.object_class) ||
2090 !(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
2094 g_assert (sp >= stack);
2096 if (!calli && mono_jit_inline_code && !virtual && cm->inline_count != -1 &&
2097 cm != method && (cm->inline_info || check_inlining (cm) >= 0)) {
2098 MonoInlineInfo *ii = alloca (sizeof (MonoInlineInfo));
2102 /* avoid recursive inlining */
2103 for (l = inline_list; l; l = l->next) {
2104 if (((MonoInlineInfo *)l->data)->method == cm)
2110 /* make sure runtime_init is called */
2111 mono_class_vtable (cfg->domain, cm->klass);
2113 mono_jit_stats.inlined_methods++;
2115 if (cm->signature->hasthis)
2118 args = cm->signature->param_count + cm->signature->hasthis;
2122 ii->saved_image = image;
2123 ii->arg_map = alloca (args * sizeof (MBTree *));
2124 memcpy (ii->arg_map, sp, args * sizeof (MBTree *));
2126 if (cm->signature->hasthis && !cm->uses_this &&
2127 (ii->arg_map [0]->op != MB_TERM_CHECKTHIS)) {
2128 ii->arg_map [0] = mono_ctree_new (mp, MB_TERM_CHECKTHIS,
2129 ii->arg_map [0], NULL);
2130 ADD_TREE (ii->arg_map [0], ii->arg_map [0]->cli_addr);
2133 if (cm->inline_count) {
2134 inline_list = g_list_prepend (inline_list, ii);
2135 ip = ((MonoMethodNormal *)cm)->header->code;
2136 ii->end = ip + cm->inline_count;
2137 arg_map = ii->arg_map;
2138 image = cm->klass->image;
2145 MonoMethod *wrapper;
2146 if (cm->signature->pinvoke) {
2147 #ifdef MONO_USE_EXC_TABLES
2148 if (mono_method_blittable (cm)) {
2149 csig = cm->signature;
2152 wrapper = mono_marshal_get_native_wrapper (cm);
2153 csig = wrapper->signature;
2154 #ifdef MONO_USE_EXC_TABLES
2158 csig = cm->signature;
2161 nargs = csig->param_count;
2163 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
2164 g_assert (!virtual || csig->hasthis);
2166 if (!calli && cm->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
2167 if (cm->klass->parent == mono_defaults.array_class) {
2168 array_rank = cm->klass->rank;
2170 if (cm->name [0] == 'S') /* Set */
2175 if (csig->param_count + 1 < 10)
2176 arg_info = default_arg_info;
2178 arg_info = g_new (MonoJitArgumentInfo, csig->param_count + 1);
2180 frame_size = arch_get_argument_info (csig, nargs, arg_info);
2182 for (k = nargs - 1; k >= 0; k--) {
2183 g_assert (arg_sp [k]);
2184 t1 = mono_ctree_new (mp, mono_map_arg_type (csig->params [k]), arg_sp [k], NULL);
2185 t1->data.arg_info = arg_info [k + 1];
2186 ADD_TREE (t1, arg_sp [k]->cli_addr);
2192 this = mono_ctree_new_leaf (mp, MB_TERM_NOP);
2195 if (MONO_TYPE_ISSTRUCT (csig->ret) && !array_rank) {
2198 size = mono_class_native_size (csig->ret->data.klass, &align);
2200 size = mono_class_value_size (csig->ret->data.klass, &align);
2202 vtype_num = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, VAL_UNKNOWN);
2207 t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2208 t2->data.p = ves_array_element_address;
2210 t1 = mono_ctree_new (mp, MB_TERM_CALL_I4, this, t2);
2211 t1->data.call_info.vtype_num = vtype_num;
2212 t1->data.call_info.frame_size = frame_size;
2213 t1->data.call_info.pad = arg_info [0].pad;
2214 t1->svt = VAL_POINTER;
2216 t1 = mono_store_tree (cfg, -1, t1, &t2);
2218 ADD_TREE (t1, cli_addr);
2220 if (cm->name [0] == 'G') { /* Get */
2221 t1 = mono_ctree_new (mp, mono_map_ldind_type (csig->ret, &svt), t2, NULL);
2223 PUSH_TREE (t1, t1->svt);
2224 } else if (cm->name [0] == 'S') { /* Set */
2225 t1 = ctree_create_store (cfg, csig->params [nargs], t2, arg_sp [nargs], FALSE);
2226 ADD_TREE (t1, cli_addr);
2227 } else if (cm->name [0] == 'A') { /* Address */
2228 PUSH_TREE (t2, t1->svt);
2230 g_assert_not_reached ();
2237 } else if (virtual || (csig->hasthis &&
2238 !(cm->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
2239 (cm->klass->marshalbyref || shared_to_unshared_call))) {
2241 mono_class_init (cm->klass);
2243 if (cm->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
2244 t2 = mono_ctree_new_leaf (mp, MB_TERM_INTF_ADDR);
2246 t2 = mono_ctree_new_leaf (mp, MB_TERM_VFUNC_ADDR);
2251 t2 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
2252 t2->data.nonvirt_info.p = arch_create_jit_trampoline (cm);
2253 t2->data.nonvirt_info.method = cm;
2257 t1 = mono_ctree_new (mp, mono_map_call_type (csig->ret, &svt), this, t2);
2258 t1->data.call_info.vtype_num = vtype_num;
2259 t1->data.call_info.frame_size = frame_size;
2260 t1->data.call_info.pad = arg_info [0].pad;
2263 if (csig->ret->type != MONO_TYPE_VOID) {
2266 ADD_TREE (t1, cli_addr);
2267 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2268 t1->data.i = vtype_num;
2269 PUSH_TREE (t1, VAL_POINTER);
2271 t1 = mono_store_tree (cfg, -1, t1, &t2);
2273 ADD_TREE (t1, cli_addr);
2274 PUSH_TREE (t2, t2->svt);
2277 ADD_TREE (t1, cli_addr);
2280 if (csig->param_count > 9)
2289 token = read32 (ip);
2292 c = mono_class_get (image, token);
2294 mono_class_init (c);
2296 t1 = mono_ctree_new (mp, MB_TERM_ISINST, *sp, NULL);
2299 PUSH_TREE (t1, VAL_POINTER);
2304 case CEE_CASTCLASS: {
2308 token = read32 (ip);
2311 c = mono_class_get (image, token);
2313 mono_class_init (c);
2315 t1 = mono_ctree_new (mp, MB_TERM_CASTCLASS, *sp, NULL);
2318 PUSH_TREE (t1, VAL_POINTER);
2323 case CEE_LDC_I4_S: {
2325 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2326 t1->data.i = *(const gint8 *)ip;
2328 PUSH_TREE (t1, VAL_I32);
2333 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2334 t1->data.i = read32 (ip);
2336 PUSH_TREE (t1, VAL_I32);
2348 case CEE_LDC_I4_8: {
2349 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2350 t1->data.i = (*ip) - CEE_LDC_I4_0;
2352 PUSH_TREE (t1, VAL_I32);
2356 //fixme: don't know if this is portable ?
2358 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2360 PUSH_TREE (t1, VAL_POINTER);
2365 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I8);
2366 t1->data.l = read64 (ip);
2368 PUSH_TREE (t1, VAL_I64);
2372 float *f = mono_alloc_static (sizeof (float));
2374 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_R4);
2378 PUSH_TREE (t1, VAL_DOUBLE);
2382 double *d = mono_alloc_static (sizeof (double));
2384 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_R8);
2388 PUSH_TREE (t1, VAL_DOUBLE);
2395 int n = (*ip) - CEE_LDLOC_0;
2398 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2399 t1->data.i = LOCAL_POS (n);
2400 if (!MONO_TYPE_ISSTRUCT (LOCAL_TYPE (n)))
2401 t1 = ctree_create_load (cfg, LOCAL_TYPE (n), t1, &svt, FALSE);
2402 PUSH_TREE (t1, svt);
2408 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2409 t1->data.i = LOCAL_POS (*ip);
2410 if (!MONO_TYPE_ISSTRUCT (LOCAL_TYPE (*ip)))
2411 t1 = ctree_create_load (cfg, LOCAL_TYPE (*ip), t1, &svt, FALSE);
2414 PUSH_TREE (t1, svt);
2417 case CEE_LDLOCA_S: {
2420 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2421 t1->data.i = LOCAL_POS (*ip);
2422 VARINFO (cfg, t1->data.i).isvolatile = 1;
2424 PUSH_TREE (t1, VAL_POINTER);
2431 int n = (*ip) - CEE_STLOC_0;
2435 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2436 t1->data.i = LOCAL_POS (n);
2438 if ((t2 = mono_stack_duplicate_used_var (cfg, stack, sp, t1->data.i)))
2439 ADD_TREE (t2, cli_addr);
2441 t1 = ctree_create_store (cfg, LOCAL_TYPE (n), t1, *sp, FALSE);
2442 ADD_TREE (t1, cli_addr);
2449 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2450 t1->data.i = LOCAL_POS (*ip);
2451 if ((t2 = mono_stack_duplicate_used_var (cfg, stack, sp, t1->data.i)))
2452 ADD_TREE (t2, cli_addr);
2454 t1 = ctree_create_store (cfg, LOCAL_TYPE (*ip), t1, *sp, FALSE);
2456 ADD_TREE (t1, cli_addr);
2463 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4)
2464 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i + sp [1]->data.i);
2466 t1 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], sp [1]);
2467 PUSH_TREE (t1, sp [0]->svt);
2474 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4)
2475 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i - sp [1]->data.i);
2477 t1 = mono_ctree_new (mp, MB_TERM_SUB, sp [0], sp [1]);
2478 PUSH_TREE (t1, sp [0]->svt);
2485 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4)
2486 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i & sp [1]->data.i);
2488 t1 = mono_ctree_new (mp, MB_TERM_AND, sp [0], sp [1]);
2489 PUSH_TREE (t1, sp [0]->svt);
2496 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4)
2497 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i | sp [1]->data.i);
2499 t1 = mono_ctree_new (mp, MB_TERM_OR, sp [0], sp [1]);
2500 PUSH_TREE (t1, sp [0]->svt);
2507 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4)
2508 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i ^ sp [1]->data.i);
2510 t1 = mono_ctree_new (mp, MB_TERM_XOR, sp [0], sp [1]);
2511 PUSH_TREE (t1, sp [0]->svt);
2518 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4) {
2519 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i * sp [1]->data.i);
2520 PUSH_TREE (t1, sp [0]->svt);
2522 MAKE_SPILLED_BI_ALU1 (MUL, sp [0], sp [1])
2530 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4
2531 && (sp[1]->data.i != 0)
2532 && ((sp[0]->data.i != 0x080000000) || (sp[1]->data.i != -1))) {
2533 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i / sp [1]->data.i);
2534 PUSH_TREE (t1, sp [0]->svt);
2536 MAKE_SPILLED_BI_ALU1 (DIV, sp [0], sp [1])
2544 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4) {
2545 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i % sp [1]->data.i);
2546 PUSH_TREE (t1, sp [0]->svt);
2548 MAKE_SPILLED_BI_ALU1 (REM, sp [0], sp [1])
2556 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4) {
2557 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i << sp [1]->data.i);
2558 PUSH_TREE (t1, sp [0]->svt);
2560 MAKE_SPILLED_BI_ALU1 (SHL, sp [0], sp [1])
2568 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4) {
2569 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i >> sp [1]->data.i);
2570 PUSH_TREE (t1, sp [0]->svt);
2572 MAKE_SPILLED_BI_ALU1 (SHR, sp [0], sp [1])
2577 MAKE_BI_ALU (ADD_OVF)
2578 MAKE_BI_ALU (ADD_OVF_UN)
2579 MAKE_BI_ALU (SUB_OVF)
2580 MAKE_BI_ALU (SUB_OVF_UN)
2581 MAKE_SPILLED_BI_ALU (SHR_UN)
2582 MAKE_SPILLED_BI_ALU (MUL_OVF)
2583 MAKE_SPILLED_BI_ALU (MUL_OVF_UN)
2584 MAKE_SPILLED_BI_ALU (DIV_UN)
2585 MAKE_SPILLED_BI_ALU (REM_UN)
2587 MAKE_LDIND (LDIND_I1, MB_TERM_LDIND_I1, VAL_I32)
2588 MAKE_LDIND (LDIND_U1, MB_TERM_LDIND_U1, VAL_I32)
2589 MAKE_LDIND (LDIND_I2, MB_TERM_LDIND_I2, VAL_I32)
2590 MAKE_LDIND (LDIND_U2, MB_TERM_LDIND_U2, VAL_I32)
2591 MAKE_LDIND (LDIND_I, MB_TERM_LDIND_I4, VAL_I32)
2592 MAKE_LDIND (LDIND_I4, MB_TERM_LDIND_I4, VAL_I32)
2593 MAKE_LDIND (LDIND_REF, MB_TERM_LDIND_REF, VAL_POINTER)
2594 MAKE_LDIND (LDIND_U4, MB_TERM_LDIND_U4, VAL_I32)
2595 MAKE_LDIND (LDIND_I8, MB_TERM_LDIND_I8, VAL_I64)
2596 MAKE_LDIND (LDIND_R4, MB_TERM_LDIND_R4, VAL_DOUBLE)
2597 MAKE_LDIND (LDIND_R8, MB_TERM_LDIND_R8, VAL_DOUBLE)
2599 MAKE_STIND (STIND_I1, MB_TERM_STIND_I1)
2600 MAKE_STIND (STIND_I2, MB_TERM_STIND_I2)
2601 MAKE_STIND (STIND_I, MB_TERM_STIND_I4)
2602 MAKE_STIND (STIND_I4, MB_TERM_STIND_I4)
2603 MAKE_STIND (STIND_I8, MB_TERM_STIND_I8)
2604 MAKE_STIND (STIND_R4, MB_TERM_STIND_R4)
2605 MAKE_STIND (STIND_R8, MB_TERM_STIND_R8)
2606 MAKE_STIND (STIND_REF, MB_TERM_STIND_REF)
2608 MAKE_LDELEM (LDELEM_I1, MB_TERM_LDIND_I1, VAL_I32, 1)
2609 MAKE_LDELEM (LDELEM_U1, MB_TERM_LDIND_U1, VAL_I32, 1)
2610 MAKE_LDELEM (LDELEM_I2, MB_TERM_LDIND_I2, VAL_I32, 2)
2611 MAKE_LDELEM (LDELEM_U2, MB_TERM_LDIND_U2, VAL_I32, 2)
2612 MAKE_LDELEM (LDELEM_I, MB_TERM_LDIND_I4, VAL_I32, 4)
2613 MAKE_LDELEM (LDELEM_I4, MB_TERM_LDIND_I4, VAL_I32, 4)
2614 MAKE_LDELEM (LDELEM_REF, MB_TERM_LDIND_REF, VAL_POINTER, sizeof (gpointer))
2615 MAKE_LDELEM (LDELEM_U4, MB_TERM_LDIND_U4, VAL_I32, 4)
2616 MAKE_LDELEM (LDELEM_I8, MB_TERM_LDIND_I8, VAL_I64, 8)
2617 MAKE_LDELEM (LDELEM_R4, MB_TERM_LDIND_R4, VAL_DOUBLE, 4)
2618 MAKE_LDELEM (LDELEM_R8, MB_TERM_LDIND_R8, VAL_DOUBLE, 8)
2620 MAKE_STELEM (STELEM_I1, MB_TERM_STIND_I1, 1)
2621 MAKE_STELEM (STELEM_I2, MB_TERM_STIND_I2, 2)
2622 MAKE_STELEM (STELEM_I4, MB_TERM_STIND_I4, 4)
2623 MAKE_STELEM (STELEM_I, MB_TERM_STIND_I4, 4)
2624 MAKE_STELEM (STELEM_REF, MB_TERM_STIND_REF, sizeof (gpointer))
2625 MAKE_STELEM (STELEM_I8, MB_TERM_STIND_I8, 8)
2626 MAKE_STELEM (STELEM_R4, MB_TERM_STIND_R4, 4)
2627 MAKE_STELEM (STELEM_R8, MB_TERM_STIND_R8, 8)
2632 if (sp [0]->op == MB_TERM_CONST_I4)
2633 t1 = mono_ctree_new_icon4 (mp, -sp [0]->data.i);
2635 t1 = mono_ctree_new (mp, MB_TERM_NEG, sp [0], NULL);
2636 PUSH_TREE (t1, sp [0]->svt);
2642 if (sp [0]->op == MB_TERM_CONST_I4)
2643 t1 = mono_ctree_new_icon4 (mp, ~sp [0]->data.i);
2645 t1 = mono_ctree_new (mp, MB_TERM_NOT, sp [0], NULL);
2646 PUSH_TREE (t1, sp [0]->svt);
2652 int br_s = (*ip == CEE_BR_S);
2656 target = cli_addr + 2 + (signed char) *ip;
2658 target = cli_addr + 5 + (gint32) read32(ip);
2660 g_assert (target >= 0 && target <= header->code_size);
2661 g_assert (bcinfo [target].is_block_start);
2662 tbb = &cfg->bblocks [bcinfo [target].block_id];
2663 create_outstack (cfg, bb, stack, sp - stack);
2664 mark_reached (cfg, tbb, bb->outstack, bb->outdepth);
2666 t1 = mono_ctree_new_leaf (mp, MB_TERM_BR);
2668 ADD_TREE (t1, cli_addr);
2675 superblock_end = TRUE;
2682 token = read32 (ip);
2685 cm = mono_get_method (method->klass->image, token, NULL);
2688 t1 = mono_ctree_new_leaf (mp, MB_TERM_JMP);
2689 /* fixme: our magic trampoline code does not work in this case,
2690 * so I need to compile the method immediately */
2691 t1->data.p = mono_compile_method (cm);;
2693 ADD_TREE (t1, cli_addr);
2700 int leave_s = (*ip == CEE_LEAVE_S);
2704 target = cli_addr + 2 + (signed char) *ip;
2706 target = cli_addr + 5 + (gint32) read32(ip);
2708 g_assert (target >= 0 && target <= header->code_size);
2709 g_assert (bcinfo [target].is_block_start);
2710 tbb = &cfg->bblocks [bcinfo [target].block_id];
2712 /* empty the stack */
2713 while (sp != stack) {
2715 t1 = mono_ctree_new (mp, MB_TERM_POP, *sp, NULL);
2716 ADD_TREE (t1, cli_addr);
2719 mark_reached (cfg, tbb, NULL, 0);
2721 /* fixme: fault handler */
2723 if ((hb = mono_find_final_block (cfg, cli_addr, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
2724 mark_reached (cfg, hb, NULL, 0);
2725 t1 = mono_ctree_new_leaf (mp, MB_TERM_HANDLER);
2727 ADD_TREE (t1, cli_addr);
2730 /* check if we leave a catch handler, if so we have to
2731 * rethrow ThreadAbort exceptions */
2732 for (k = 0; k < header->num_clauses; ++k) {
2733 MonoExceptionClause *clause = &header->clauses [k];
2734 if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE &&
2735 MONO_OFFSET_IN_HANDLER (clause, cli_addr)) {
2736 t1 = mono_ctree_new_leaf (mp, MB_TERM_RETHROW_ABORT);
2737 t1->data.i = mono_allocate_excvar (cfg);
2738 ADD_TREE (t1, cli_addr);
2743 t1 = mono_ctree_new_leaf (mp, MB_TERM_BR);
2745 ADD_TREE (t1, cli_addr);
2752 superblock_end = TRUE;
2769 case CEE_BRTRUE_S: {
2771 int near_jump = *ip == CEE_BRTRUE_S;
2775 t1 = mono_ctree_new (mp, MB_TERM_BRTRUE, sp [0], NULL);
2778 target = cli_addr + 2 + (signed char) *ip;
2780 target = cli_addr + 5 + (gint32) read32 (ip);
2782 g_assert (target >= 0 && target <= header->code_size);
2783 g_assert (bcinfo [target].is_block_start);
2784 tbb = &cfg->bblocks [bcinfo [target].block_id];
2785 create_outstack (cfg, bb, stack, sp - stack);
2786 mark_reached (cfg, tbb, bb->outstack, bb->outdepth);
2789 ip += near_jump ? 1: 4;
2790 ADD_TREE (t1, cli_addr);
2794 case CEE_BRFALSE_S: {
2796 int near_jump = *ip == CEE_BRFALSE_S;
2800 t1 = mono_ctree_new (mp, MB_TERM_BRFALSE, sp [0], NULL);
2803 target = cli_addr + 2 + (signed char) *ip;
2805 target = cli_addr + 5 + (gint32) read32 (ip);
2807 g_assert (target >= 0 && target <= header->code_size);
2808 g_assert (bcinfo [target].is_block_start);
2809 tbb = &cfg->bblocks [bcinfo [target].block_id];
2810 create_outstack (cfg, bb, stack, sp - stack);
2811 mark_reached (cfg, tbb, bb->outstack, bb->outdepth);
2814 ip += near_jump ? 1: 4;
2815 ADD_TREE (t1, cli_addr);
2819 MonoType *ret = signature->ret;
2823 if (ret->type != MONO_TYPE_VOID) {
2825 if (MONO_TYPE_ISSTRUCT (ret)) {
2827 t1 = mono_ctree_new (mp, MB_TERM_RET_OBJ, *sp, NULL);
2828 t1->data.i = mono_class_value_size (ret->data.klass, &align);
2830 t1 = mono_ctree_new (mp, MB_TERM_RET, *sp, NULL);
2833 t1 = mono_ctree_new_leaf (mp, MB_TERM_RET_VOID);
2836 t1->last_instr = (ip == (header->code + header->code_size));
2838 ADD_TREE (t1, cli_addr);
2841 g_warning ("more values on stack at %s IL_%04x: %d",
2842 mono_method_full_name (method, TRUE),
2843 ip - header->code, sp - stack);
2844 mono_print_ctree (cfg, sp [-1]);
2847 superblock_end = TRUE;
2850 case CEE_ENDFINALLY: {
2853 t1 = mono_ctree_new_leaf (mp, MB_TERM_ENDFINALLY);
2854 ADD_TREE (t1, cli_addr);
2855 t1->last_instr = FALSE;
2857 g_assert (sp == stack);
2858 superblock_end = TRUE;
2865 int n = (*ip) - CEE_LDARG_0;
2872 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2873 t1->data.i = ARG_POS (n);
2874 if (!MONO_TYPE_ISSTRUCT (ARG_TYPE (n)))
2875 t1 = ctree_create_load (cfg, ARG_TYPE (n), t1, &svt, TRUE);
2877 PUSH_TREE (t1, svt);
2886 *sp = arg_map [*ip];
2889 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2890 t1->data.i = ARG_POS (*ip);
2891 if (!MONO_TYPE_ISSTRUCT (ARG_TYPE (*ip)))
2892 t1 = ctree_create_load (cfg, ARG_TYPE (*ip), t1, &svt, TRUE);
2893 PUSH_TREE (t1, svt);
2898 case CEE_LDARGA_S: {
2900 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2901 t1->data.i = ARG_POS (*ip);
2902 PUSH_TREE (t1, VAL_POINTER);
2910 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2911 t1->data.i = ARG_POS (*ip);
2912 t1 = ctree_create_store (cfg, ARG_TYPE (*ip), t1, *sp, TRUE);
2914 ADD_TREE (t1, cli_addr);
2922 /* fixme: maybe we should add more of these optimisations */
2923 if (sp [-1]->op == MB_TERM_CONST_I4) {
2925 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2926 t1->data.i = sp [-1]->data.i;
2927 PUSH_TREE (t1, VAL_I32);
2932 vnum = mono_allocate_intvar (cfg, sp - stack, sp [0]->svt);
2933 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2936 t2 = mono_ctree_new (mp, mono_map_store_svt_type (sp [0]->svt), t1, sp [0]);
2937 t2->svt = sp [0]->svt;
2938 ADD_TREE (t2, cli_addr);
2940 t1 = ctree_create_dup (mp, t2);
2941 PUSH_TREE (t1, t1->svt);
2942 t1 = ctree_create_dup (mp, t1);
2943 PUSH_TREE (t1, t1->svt);
2951 t1 = mono_ctree_new (mp, MB_TERM_POP, *sp, NULL);
2952 ADD_TREE (t1, cli_addr);
2956 case CEE_CKFINITE: {
2961 /* this instr. can throw exceptions as side effect,
2962 * so we cant eliminate dead code which contains CKFINITE opdodes.
2963 * Spilling to memory makes sure that we always perform
2965 vnum = mono_allocate_intvar (cfg, sp - stack, sp [0]->svt);
2966 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2969 t2 = mono_ctree_new (mp, MB_TERM_CKFINITE, *sp, NULL);
2971 t2 = mono_ctree_new (mp, mono_map_store_svt_type (sp [0]->svt), t1, t2);
2972 t2->svt = sp [0]->svt;
2973 ADD_TREE (t2, cli_addr);
2975 t1 = ctree_create_dup (mp, t2);
2976 PUSH_TREE (t1, t1->svt);
2982 if (sp [0]->op == MB_TERM_CONST_I4)
2983 t1 = mono_ctree_new_icon4 (mp, (guint8)sp [0]->data.i);
2985 t1 = mono_ctree_new (mp, MB_TERM_CONV_U1, *sp, NULL);
2986 PUSH_TREE (t1, VAL_I32);
2991 if (sp [0]->op == MB_TERM_CONST_I4)
2992 t1 = mono_ctree_new_icon4 (mp, (gint8)sp [0]->data.i);
2994 t1 = mono_ctree_new (mp, MB_TERM_CONV_I1, *sp, NULL);
2995 PUSH_TREE (t1, VAL_I32);
3000 if (sp [0]->op == MB_TERM_CONST_I4)
3001 t1 = mono_ctree_new_icon4 (mp, (guint16)sp [0]->data.i);
3003 t1 = mono_ctree_new (mp, MB_TERM_CONV_U2, *sp, NULL);
3004 PUSH_TREE (t1, VAL_I32);
3009 if (sp [0]->op == MB_TERM_CONST_I4)
3010 t1 = mono_ctree_new_icon4 (mp, (gint16)sp [0]->data.i);
3012 t1 = mono_ctree_new (mp, MB_TERM_CONV_I2, *sp, NULL);
3013 PUSH_TREE (t1, VAL_I32);
3019 if (sp [0]->op == MB_TERM_CONST_I4)
3022 t1 = mono_ctree_new (mp, MB_TERM_CONV_I4, *sp, NULL);
3023 PUSH_TREE (t1, VAL_I32);
3029 if (sp [0]->op == MB_TERM_CONST_I4)
3032 t1 = mono_ctree_new (mp, MB_TERM_CONV_U4, *sp, NULL);
3033 PUSH_TREE (t1, VAL_I32);
3038 t1 = mono_ctree_new (mp, MB_TERM_CONV_I8, *sp, NULL);
3039 PUSH_TREE (t1, VAL_I64);
3044 t1 = mono_ctree_new (mp, MB_TERM_CONV_U8, *sp, NULL);
3045 PUSH_TREE (t1, VAL_I64);
3050 t1 = mono_ctree_new (mp, MB_TERM_CONV_R8, *sp, NULL);
3051 PUSH_TREE (t1, VAL_DOUBLE);
3056 t1 = mono_ctree_new (mp, MB_TERM_CONV_R4, *sp, NULL);
3057 PUSH_TREE (t1, VAL_DOUBLE);
3062 t1 = mono_ctree_new (mp, MB_TERM_CONV_R_UN, *sp, NULL);
3063 PUSH_TREE (t1, VAL_DOUBLE);
3065 case CEE_CONV_OVF_I:
3066 case CEE_CONV_OVF_I4:
3069 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I4, *sp, NULL);
3070 PUSH_TREE (t1, VAL_I32);
3072 case CEE_CONV_OVF_I_UN:
3073 case CEE_CONV_OVF_I4_UN:
3076 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I4_UN, *sp, NULL);
3077 PUSH_TREE (t1, VAL_I32);
3079 case CEE_CONV_OVF_U:
3080 case CEE_CONV_OVF_U4:
3083 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U4, *sp, NULL);
3084 PUSH_TREE (t1, VAL_I32);
3086 case CEE_CONV_OVF_I1:
3089 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I1, *sp, NULL);
3090 PUSH_TREE (t1, VAL_I32);
3092 case CEE_CONV_OVF_I1_UN:
3095 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I1_UN, *sp, NULL);
3096 PUSH_TREE (t1, VAL_I32);
3098 case CEE_CONV_OVF_U1_UN:
3101 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U1_UN, *sp, NULL);
3102 PUSH_TREE (t1, VAL_I32);
3104 case CEE_CONV_OVF_U1:
3107 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U1, *sp, NULL);
3108 PUSH_TREE (t1, VAL_I32);
3110 case CEE_CONV_OVF_I2:
3113 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I2, *sp, NULL);
3114 PUSH_TREE (t1, VAL_I32);
3116 case CEE_CONV_OVF_U2_UN:
3119 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U2_UN, *sp, NULL);
3120 PUSH_TREE (t1, VAL_I32);
3122 case CEE_CONV_OVF_U2:
3125 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U2, *sp, NULL);
3126 PUSH_TREE (t1, VAL_I32);
3128 case CEE_CONV_OVF_I2_UN:
3131 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I2_UN, *sp, NULL);
3132 PUSH_TREE (t1, VAL_I32);
3134 case CEE_CONV_OVF_U8:
3137 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U8, *sp, NULL);
3138 PUSH_TREE (t1, VAL_I32);
3140 case CEE_CONV_OVF_U_UN:
3141 case CEE_CONV_OVF_U4_UN:
3142 // fixme: raise exceptions ?
3145 t1 = mono_ctree_new (mp, MB_TERM_CONV_I4, *sp, NULL);
3146 PUSH_TREE (t1, VAL_I32);
3148 case CEE_CONV_OVF_I8_UN:
3149 case CEE_CONV_OVF_U8_UN: /* FIXME: slightly incorrect, but non worth fixing the corner cases in the old jit */
3152 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I8_UN, *sp, NULL);
3153 PUSH_TREE (t1, VAL_I64);
3155 case MONO_CUSTOM_PREFIX: {
3159 case CEE_MONO_FUNC1: {
3160 MonoMarshalConv conv;
3168 t1 = mono_ctree_new (mp, MB_TERM_FUNC1, *sp, NULL);
3171 case MONO_MARSHAL_CONV_STR_LPWSTR:
3172 t1->data.p = mono_string_to_utf16;
3174 case MONO_MARSHAL_CONV_LPWSTR_STR:
3175 t1->data.p = mono_string_from_utf16;
3177 case MONO_MARSHAL_CONV_LPSTR_STR:
3178 t1->data.p = mono_string_new_wrapper;
3180 case MONO_MARSHAL_CONV_STR_LPTSTR:
3181 case MONO_MARSHAL_CONV_STR_LPSTR:
3182 t1->data.p = mono_string_to_utf8;
3184 case MONO_MARSHAL_CONV_STR_BSTR:
3185 t1->data.p = mono_string_to_bstr;
3187 case MONO_MARSHAL_CONV_STR_TBSTR:
3188 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
3189 t1->data.p = mono_string_to_ansibstr;
3191 case MONO_MARSHAL_CONV_SB_LPSTR:
3192 t1->data.p = mono_string_builder_to_utf8;
3194 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
3195 t1->data.p = mono_array_to_savearray;
3197 case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
3198 t1->data.p = mono_array_to_lparray;
3200 case MONO_MARSHAL_CONV_DEL_FTN:
3201 t1->data.p = mono_delegate_to_ftnptr;
3203 case MONO_MARSHAL_CONV_STRARRAY_STRLPARRAY:
3204 t1->data.p = mono_marshal_string_array;
3207 g_assert_not_reached ();
3209 PUSH_TREE (t1, VAL_POINTER);
3212 case CEE_MONO_PROC2: {
3213 MonoMarshalConv conv;
3219 t1 = mono_ctree_new (mp, MB_TERM_PROC2, sp [0], sp [1]);
3222 case MONO_MARSHAL_CONV_LPSTR_SB:
3223 t1->data.p = mono_string_utf8_to_builder;
3225 case MONO_MARSHAL_FREE_ARRAY:
3226 t1->data.p = mono_marshal_free_array;
3229 g_assert_not_reached ();
3231 ADD_TREE (t1, cli_addr);
3234 case CEE_MONO_PROC3: {
3235 MonoMarshalConv conv;
3242 t1 = mono_ctree_new (mp, MB_TERM_CPSRC, sp [1], sp [2]);
3243 t1 = mono_ctree_new (mp, MB_TERM_PROC3, sp [0], t1);
3246 case MONO_MARSHAL_CONV_STR_BYVALSTR:
3247 t1->data.p = mono_string_to_byvalstr;
3249 case MONO_MARSHAL_CONV_STR_BYVALWSTR:
3250 t1->data.p = mono_string_to_byvalwstr;
3253 g_assert_not_reached ();
3256 ADD_TREE (t1, cli_addr);
3259 case CEE_MONO_LDNATIVEOBJ: {
3264 token = read32 (ip);
3268 g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
3269 c = (MonoClass *)mono_method_get_wrapper_data (method, token);
3270 g_assert (c->valuetype);
3272 t1 = ctree_create_load (cfg, &c->byval_arg, *sp, &svt, FALSE);
3273 PUSH_TREE (t1, svt);
3276 case CEE_MONO_FREE: {
3280 t1 = mono_ctree_new (mp, MB_TERM_FREE, *sp, NULL);
3281 ADD_TREE (t1, cli_addr);
3284 case CEE_MONO_OBJADDR: {
3288 t1 = mono_ctree_new (mp, MB_TERM_OBJADDR, *sp, NULL);
3289 PUSH_TREE (t1, VAL_POINTER);
3292 case CEE_MONO_VTADDR: {
3296 t1 = mono_ctree_new (mp, MB_TERM_VTADDR, *sp, NULL);
3297 PUSH_TREE (t1, VAL_POINTER);
3300 case CEE_MONO_LDPTR: {
3304 token = read32 (ip);
3307 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
3308 t1->data.p = mono_method_get_wrapper_data (method, token);
3310 PUSH_TREE (t1, VAL_POINTER);
3313 case CEE_MONO_NEWOBJ: {
3318 token = read32 (ip);
3321 class = (MonoClass *)mono_method_get_wrapper_data (method, token);
3323 t1 = mono_ctree_new_leaf (mp, MB_TERM_NEWOBJ);
3325 PUSH_TREE (t1, VAL_POINTER);
3329 case CEE_MONO_RETOBJ: {
3330 MonoType *ret = signature->ret;
3335 token = read32 (ip);
3338 class = (MonoClass *)mono_method_get_wrapper_data (method, token);
3342 g_assert (MONO_TYPE_ISSTRUCT (ret));
3344 t1 = ctree_create_load (cfg, &class->byval_arg, *sp, &svt, FALSE);
3345 t1 = mono_ctree_new (mp, MB_TERM_RET_OBJ, t1, NULL);
3346 t1->data.i = mono_class_native_size (ret->data.klass, NULL);
3347 t1->last_instr = (ip == (header->code + header->code_size));
3349 ADD_TREE (t1, cli_addr);
3352 g_warning ("more values on stack at %s IL_%04x: %d",
3353 mono_method_full_name (method, TRUE),
3354 ip - header->code, sp - stack);
3355 mono_print_ctree (cfg, sp [-1]);
3358 superblock_end = TRUE;
3362 g_error ("Unimplemented opcode at IL_%04x "
3363 "%02x %02x", ip - header->code, MONO_CUSTOM_PREFIX, *ip);
3371 case CEE_ENDFILTER: {
3375 t1 = mono_ctree_new (mp, MB_TERM_ENDFILTER, *sp, NULL);
3376 ADD_TREE (t1, cli_addr);
3377 t1->last_instr = FALSE;
3379 g_assert (sp == stack);
3380 superblock_end = TRUE;
3389 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3390 t1->data.i = LOCAL_POS (n);
3391 if (!MONO_TYPE_ISSTRUCT (LOCAL_TYPE (n)))
3392 t1 = ctree_create_load (cfg, LOCAL_TYPE (n), t1, &svt, FALSE);
3395 PUSH_TREE (t1, svt);
3401 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3402 t1->data.i = LOCAL_POS (read16 (ip));
3403 VARINFO (cfg, t1->data.i).isvolatile = 1;
3405 PUSH_TREE (t1, VAL_POINTER);
3412 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3413 t1->data.i = LOCAL_POS (read16 (ip));
3414 if ((t2 = mono_stack_duplicate_used_var (cfg, stack, sp, t1->data.i)))
3415 ADD_TREE (t2, cli_addr);
3417 t1 = ctree_create_store (cfg, LOCAL_TYPE (read16 (ip)), t1, *sp, FALSE);
3419 ADD_TREE (t1, cli_addr);
3427 arg_pos = read16 (ip);
3430 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3431 t1->data.i = ARG_POS (arg_pos);
3432 t1 = ctree_create_store (cfg, ARG_TYPE (arg_pos), t1, *sp, TRUE);
3433 ADD_TREE (t1, cli_addr);
3445 t1 = mono_ctree_new_leaf (mp, MB_TERM_RETHROW);
3446 t1->data.i = mono_allocate_excvar (cfg);
3447 ADD_TREE (t1, cli_addr);
3454 token = read32 (ip);
3457 if (method->wrapper_type != MONO_WRAPPER_NONE)
3458 cm = (MonoMethod *)mono_method_get_wrapper_data (method, token);
3460 cm = mono_get_method (image, token, NULL);
3464 t1 = mono_ctree_new_leaf (mp, MB_TERM_LDFTN);
3466 PUSH_TREE (t1, VAL_POINTER);
3469 case CEE_LDVIRTFTN: {
3473 token = read32 (ip);
3477 cm = mono_get_method (image, token, NULL);
3480 if (cm->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
3481 t2 = mono_ctree_new_leaf (mp, MB_TERM_INTF_ADDR);
3483 t2 = mono_ctree_new_leaf (mp, MB_TERM_VFUNC_ADDR);
3487 t1 = mono_ctree_new (mp, MB_TERM_LDVIRTFTN, *sp, t2);
3489 PUSH_TREE (t1, VAL_POINTER);
3498 token = read32 (ip);
3499 class = mono_class_get (image, token);
3503 t1 = mono_ctree_new (mp, MB_TERM_INITOBJ, *sp, NULL);
3504 t1->data.i = mono_class_value_size (class, NULL);
3505 ADD_TREE (t1, cli_addr);
3515 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3516 t1->data.i = ARG_POS (n);
3517 if (!MONO_TYPE_ISSTRUCT (ARG_TYPE (n)))
3518 t1 = ctree_create_load (cfg, ARG_TYPE (n), t1, &svt, TRUE);
3519 PUSH_TREE (t1, svt);
3528 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3529 t1->data.i = ARG_POS (n);
3530 PUSH_TREE (t1, svt);
3537 token = read32 (ip);
3540 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
3541 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
3542 MonoType *type = mono_type_create_from_typespec (image, token);
3543 t1->data.i = mono_type_size (type, &align);
3544 mono_metadata_free_type (type);
3546 MonoClass *szclass = mono_class_get (image, token);
3547 mono_class_init (szclass);
3548 g_assert (szclass->valuetype);
3549 t1->data.i = mono_class_value_size (szclass, &align);
3552 PUSH_TREE (t1, VAL_I32);
3559 t1 = mono_ctree_new (mp, MB_TERM_CPSRC, sp [1], sp [2]);
3560 t1 = mono_ctree_new (mp, MB_TERM_CPBLK, sp [0], t1);
3561 ADD_TREE (t1, cli_addr);
3564 case CEE_UNALIGNED_: {
3566 /* fixme: implement me */
3569 case CEE_VOLATILE_: {
3571 /* fixme: implement me */
3576 tail_recursion = TRUE;
3578 case CEE_LOCALLOC: {
3582 t1 = mono_ctree_new (mp, MB_TERM_LOCALLOC, *sp, NULL);
3583 t1->data.i = header->init_locals;
3584 PUSH_TREE (t1, VAL_POINTER);
3591 t1 = mono_ctree_new (mp, MB_TERM_CPSRC, sp [1], sp [2]);
3592 t1 = mono_ctree_new (mp, MB_TERM_INITBLK, sp [0], t1);
3593 ADD_TREE (t1, cli_addr);
3597 g_error ("Unimplemented opcode at IL_%04x "
3598 "0xFE %02x", ip - header->code, *ip);
3603 g_warning ("unknown instruction `%s' at IL_%04X",
3604 mono_opcode_names [*ip], ip - header->code);
3605 if (mono_debug_format == MONO_DEBUG_FORMAT_NONE) {
3608 mono_print_forest (cfg, forest);
3609 g_assert_not_reached ();
3613 if ((depth = sp - stack)) {
3614 //printf ("DEPTH %d %d\n", depth, sp [0]->op);
3615 //mono_print_forest (cfg, forest);
3616 create_outstack (cfg, bb, stack, sp - stack);
3620 superblock_end = TRUE;
3623 superblock_end = TRUE;
3624 //printf ("unreached block %d\n", i);
3626 if (repeat_count >= 10) {
3627 /*mono_print_forest (cfg, forest);
3628 g_warning ("repeat count exceeded at ip: 0x%04x in %s\n", bb->cli_addr, cfg->method->name);*/
3632 //printf ("BBE %d %d %d %d\n", i, bb->reached, bb->finished, superblock_end);
3636 //printf ("REPEAT %d\n", repeat);
3637 mono_jit_stats.analyze_stack_repeat++;
3646 mono_cfg_free (MonoFlowGraph *cfg)
3650 for (i = 0; i < cfg->block_count; i++) {
3651 if (!cfg->bblocks [i].reached)
3653 g_ptr_array_free (cfg->bblocks [i].forest, TRUE);
3654 g_list_free (cfg->bblocks [i].succ);
3658 g_free (cfg->bcinfo);
3661 g_free (cfg->bblocks);
3663 g_array_free (cfg->varinfo, TRUE);
3665 mono_mempool_destroy (cfg->mp);
3668 int mono_exc_esp_offset = 0;
3670 static MonoFlowGraph *
3671 mono_cfg_new (MonoMethod *method)
3675 MonoMemPool *mp = mono_mempool_new ();
3677 g_assert (((MonoMethodNormal *)method)->header);
3679 cfg = mono_mempool_alloc0 (mp, sizeof (MonoFlowGraph));
3681 cfg->domain = mono_domain_get ();
3682 cfg->method = method;
3685 /* reserve space to save LMF */
3686 cfg->locals_size = sizeof (MonoLMF);
3688 cfg->locals_size += sizeof (gpointer);
3689 mono_exc_esp_offset = - cfg->locals_size;
3691 cfg->locals_size += sizeof (gpointer);
3693 /* aligment check */
3694 g_assert (!(cfg->locals_size & 0x7));
3696 /* fixme: we should also consider loader optimisation attributes */
3697 cfg->share_code = mono_jit_share_code;
3699 cfg->varinfo = g_array_new (FALSE, TRUE, sizeof (MonoVarInfo));
3701 SET_VARINFO (vi, 0, 0, 0, 0);
3702 g_array_append_val (cfg->varinfo, vi); /* add invalid value at position 0 */
3704 cfg->intvars = mono_mempool_alloc0 (mp, sizeof (guint16) * VAL_DOUBLE *
3705 ((MonoMethodNormal *)method)->header->max_stack);
3707 mono_analyze_flow (cfg);
3709 if (!mono_analyze_stack (cfg)) {
3710 mono_cfg_free (cfg);
3718 mono_get_runtime_method (MonoMethod* method)
3721 const char *name = method->name;
3723 if (method->klass->parent == mono_defaults.multicastdelegate_class) {
3724 if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
3725 return (gpointer)mono_delegate_ctor;
3726 } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
3727 nm = mono_marshal_get_delegate_invoke (method);
3728 return mono_compile_method (nm);
3729 } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
3730 nm = mono_marshal_get_delegate_begin_invoke (method);
3731 return mono_compile_method (nm);
3732 } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
3733 nm = mono_marshal_get_delegate_end_invoke (method);
3734 return mono_compile_method (nm);
3740 #ifdef MONO_USE_EXC_TABLES
3742 mono_type_blittable (MonoType *type)
3747 switch (type->type){
3748 case MONO_TYPE_VOID:
3762 case MONO_TYPE_VALUETYPE:
3763 case MONO_TYPE_CLASS:
3764 return type->data.klass->blittable;
3774 mono_method_blittable (MonoMethod *method)
3776 MonoMethodSignature *sig;
3782 if (!mono_has_unwind_info (method)) {
3786 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
3789 sig = method->signature;
3791 if (!mono_type_blittable (sig->ret))
3794 for (i = 0; i < sig->param_count; i++)
3795 if (!mono_type_blittable (sig->params [i]))
3803 * mono_jit_compile_method:
3804 * @method: pointer to the method info
3806 * JIT compilation of a single method.
3808 * Returns: a pointer to the newly created code.
3811 mono_jit_compile_method (MonoMethod *method)
3813 MonoDomain *target_domain, *domain = mono_domain_get ();
3816 GHashTable *jit_code_hash;
3818 if (mono_jit_share_code)
3819 target_domain = mono_root_domain;
3821 target_domain = domain;
3823 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
3824 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
3826 if (!method->info) {
3829 if (!method->addr && (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
3830 mono_lookup_pinvoke_call (method);
3831 #ifdef MONO_USE_EXC_TABLES
3832 if (mono_method_blittable (method)) {
3833 method->info = method->addr;
3836 nm = mono_marshal_get_native_wrapper (method);
3837 method->info = mono_compile_method (nm);
3839 if (mono_debug_format != MONO_DEBUG_FORMAT_NONE)
3840 mono_debug_add_wrapper (method, nm, target_domain);
3841 #ifdef MONO_USE_EXC_TABLES
3846 return method->info;
3849 jit_code_hash = target_domain->jit_code_hash;
3851 if ((addr = g_hash_table_lookup (jit_code_hash, method))) {
3852 mono_jit_stats.methods_lookups++;
3857 mono_jit_stats.methods_compiled++;
3859 if (mono_jit_trace_calls || mono_jit_dump_asm || mono_jit_dump_forest) {
3860 printf ("Start JIT compilation of %s, domain '%s'\n",
3861 mono_method_full_name (method, TRUE), target_domain->friendly_name);
3864 if (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
3865 if (!(addr = mono_get_runtime_method (method))) {
3866 mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
3867 if (mono_debug_format != MONO_DEBUG_FORMAT_NONE)
3870 g_error ("Don't know how to exec runtime method %s", mono_method_full_name (method, TRUE));
3873 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
3875 gulong code_size_ratio;
3877 mono_profiler_method_jit (method);
3879 if (!(cfg = mono_cfg_new (method))) {
3880 mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
3884 cfg->code_size = MAX (header->code_size * 5, 256);
3885 cfg->start = cfg->code = g_malloc (cfg->code_size);
3887 if (mono_debugger_method_has_breakpoint (method))
3888 x86_breakpoint (cfg->code);
3890 if (!(ji = arch_jit_compile_cfg (target_domain, cfg))) {
3891 mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
3897 mono_jit_stats.allocated_code_size += cfg->code_size;
3899 code_size_ratio = cfg->code - cfg->start;
3900 if (code_size_ratio > mono_jit_stats.biggest_method_size) {
3901 mono_jit_stats.biggest_method_size = code_size_ratio;
3902 mono_jit_stats.biggest_method = method;
3904 code_size_ratio = (code_size_ratio * 100) / header->code_size;
3905 if (code_size_ratio > mono_jit_stats.max_code_size_ratio) {
3906 mono_jit_stats.max_code_size_ratio = code_size_ratio;
3907 mono_jit_stats.max_ratio_method = method;
3911 if (mono_jit_dump_asm) {
3912 char *id = g_strdup_printf ("%s.%s_%s", method->klass->name_space,
3913 method->klass->name, method->name);
3914 mono_disassemble_code (cfg->start, cfg->code - cfg->start, id);
3917 if (mono_debug_format != MONO_DEBUG_FORMAT_NONE)
3918 mono_debug_jit_add_method (cfg);
3921 mono_jit_stats.native_code_size += ji->code_size;
3923 ji->num_clauses = header->num_clauses;
3925 if (header->num_clauses) {
3926 int i, start_block, end_block, filter_block;
3928 ji->clauses = mono_mempool_alloc0 (target_domain->mp,
3929 sizeof (MonoJitExceptionInfo) * header->num_clauses);
3931 for (i = 0; i < header->num_clauses; i++) {
3932 MonoExceptionClause *ec = &header->clauses [i];
3933 MonoJitExceptionInfo *ei = &ji->clauses [i];
3935 ei->flags = ec->flags;
3937 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
3938 g_assert (cfg->bcinfo [ec->token_or_filter].is_block_start);
3939 filter_block = cfg->bcinfo [ec->token_or_filter].block_id;
3940 ei->data.filter = cfg->start + cfg->bblocks [filter_block].addr;
3942 ei->data.token = ec->token_or_filter;
3945 g_assert (cfg->bcinfo [ec->try_offset].is_block_start);
3946 start_block = cfg->bcinfo [ec->try_offset].block_id;
3947 end_block = cfg->bcinfo [ec->try_offset + ec->try_len].block_id;
3948 g_assert (cfg->bcinfo [ec->try_offset + ec->try_len].is_block_start);
3950 ei->try_start = cfg->start + cfg->bblocks [start_block].addr;
3951 ei->try_end = cfg->start + cfg->bblocks [end_block].addr;
3953 g_assert (cfg->bcinfo [ec->handler_offset].is_block_start);
3954 start_block = cfg->bcinfo [ec->handler_offset].block_id;
3955 ei->handler_start = cfg->start + cfg->bblocks [start_block].addr;
3959 mono_jit_info_table_add (target_domain, ji);
3961 mono_regset_free (cfg->rs);
3963 mono_cfg_free (cfg);
3965 mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
3968 if (mono_jit_trace_calls || mono_jit_dump_asm || mono_jit_dump_forest) {
3969 printf ("END JIT compilation of %s %p %p, domain '%s'\n",
3970 mono_method_full_name (method, FALSE),
3973 target_domain->friendly_name);
3976 g_hash_table_insert (jit_code_hash, method, addr);
3978 /* make sure runtime_init is called */
3979 mono_class_vtable (target_domain, method->klass);
3984 /* mono_jit_create_remoting_trampoline:
3985 * @method: pointer to the method info
3987 * Creates a trampoline which calls the remoting functions. This
3988 * is used in the vtable of transparent proxies.
3990 * Returns: a pointer to the newly created code
3993 mono_jit_create_remoting_trampoline (MonoMethod *method)
3996 guint8 *addr = NULL;
3998 nm = mono_marshal_get_remoting_invoke (method);
3999 addr = mono_compile_method (nm);
4004 /* this function is never called */
4006 ves_array_set (MonoArray *this, ...)
4008 g_assert_not_reached ();
4011 /* this function is never called */
4013 ves_array_get (MonoArray *this, ...)
4015 g_assert_not_reached ();
4020 * @assembly: reference to an assembly
4021 * @argc: argument count
4022 * @argv: argument vector
4024 * Start execution of a program.
4027 mono_jit_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
4029 MonoImage *image = assembly->image;
4032 method = mono_get_method (image, mono_image_get_entry_point (image), NULL);
4034 return mono_runtime_run_main (method, argc, argv, NULL);
4037 #ifdef PLATFORM_WIN32
4038 #define GET_CONTEXT \
4039 struct sigcontext *ctx = (struct sigcontext*)_dummy;
4041 #define GET_CONTEXT \
4042 void **_p = (void **)&_dummy; \
4043 struct sigcontext *ctx = (struct sigcontext *)++_p;
4047 sigfpe_signal_handler (int _dummy)
4052 exc = mono_get_exception_divide_by_zero ();
4054 arch_handle_exception (ctx, exc, FALSE);
4058 sigill_signal_handler (int _dummy)
4062 exc = mono_get_exception_execution_engine ("SIGILL");
4064 arch_handle_exception (ctx, exc, FALSE);
4068 sigsegv_signal_handler (int _dummy)
4073 exc = mono_get_exception_null_reference ();
4075 arch_handle_exception (ctx, exc, FALSE);
4079 sigusr1_signal_handler (int _dummy)
4084 thread = mono_thread_current ();
4086 g_assert (thread->abort_exc);
4088 arch_handle_exception (ctx, thread->abort_exc, FALSE);
4092 mono_get_lmf_addr (void)
4094 MonoJitTlsData *jit_tls;
4096 if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
4097 return &jit_tls->lmf;
4099 g_assert_not_reached ();
4104 * mono_thread_abort:
4105 * @obj: exception object
4107 * abort the thread, print exception information and stack trace
4110 mono_thread_abort (MonoObject *obj)
4112 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
4120 mono_thread_start_cb (guint32 tid, gpointer stack_start, gpointer func)
4122 MonoJitTlsData *jit_tls;
4125 jit_tls = g_new0 (MonoJitTlsData, 1);
4127 TlsSetValue (mono_jit_tls_id, jit_tls);
4129 jit_tls->abort_func = mono_thread_abort;
4130 jit_tls->end_of_stack = stack_start;
4132 lmf = g_new0 (MonoLMF, 1);
4138 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
4141 mono_thread_abort_dummy (MonoObject *obj)
4143 if (mono_thread_attach_aborted_cb)
4144 mono_thread_attach_aborted_cb (obj);
4146 mono_thread_abort (obj);
4150 mono_thread_attach_cb (guint32 tid, gpointer stack_start)
4152 MonoJitTlsData *jit_tls;
4155 jit_tls = g_new0 (MonoJitTlsData, 1);
4157 TlsSetValue (mono_jit_tls_id, jit_tls);
4159 jit_tls->abort_func = mono_thread_abort_dummy;
4160 jit_tls->end_of_stack = stack_start;
4162 lmf = g_new0 (MonoLMF, 1);
4168 static CRITICAL_SECTION ms;
4171 mono_runtime_install_handlers (void)
4173 #ifndef PLATFORM_WIN32
4174 struct sigaction sa;
4177 #ifdef PLATFORM_WIN32
4179 win32_seh_set_handler(SIGFPE, sigfpe_signal_handler);
4180 win32_seh_set_handler(SIGILL, sigill_signal_handler);
4181 win32_seh_set_handler(SIGSEGV, sigsegv_signal_handler);
4182 #else /* !PLATFORM_WIN32 */
4184 /* libpthreads has its own implementation of sigaction(),
4185 * but it seems to work well with our current exception
4186 * handlers. If not we must call syscall directly instead
4190 sa.sa_handler = sigfpe_signal_handler;
4191 sigemptyset (&sa.sa_mask);
4193 //g_assert (syscall (SYS_sigaction, SIGFPE, &sa, NULL) != -1);
4194 g_assert (sigaction (SIGFPE, &sa, NULL) != -1);
4197 sa.sa_handler = sigill_signal_handler;
4198 sigemptyset (&sa.sa_mask);
4200 //g_assert (syscall (SYS_sigaction, SIGILL, &sa, NULL) != -1);
4201 g_assert (sigaction (SIGILL, &sa, NULL) != -1);
4203 /* catch the thread abort signal */
4204 sa.sa_handler = sigusr1_signal_handler;
4205 sigemptyset (&sa.sa_mask);
4207 //g_assert (syscall (SYS_sigaction, SIGILL, &sa, NULL) != -1);
4209 g_assert (sigaction (mono_thread_get_abort_signal (), &sa, NULL) != -1);
4211 g_assert (syscall (SYS_sigaction, mono_thread_get_abort_signal (), &sa, NULL) != -1);
4212 //g_assert (sigaction (mono_thread_get_abort_signal (), &sa, NULL) != -1);
4217 sa.sa_handler = sigsegv_signal_handler;
4218 sigemptyset (&sa.sa_mask);
4220 //g_assert (syscall (SYS_sigaction, SIGSEGV, &sa, NULL) != -1);
4221 g_assert (sigaction (SIGSEGV, &sa, NULL) != -1);
4223 #endif /* PLATFORM_WIN32 */
4227 mono_jit_init (const char *file) {
4232 mono_runtime_install_handlers ();
4235 mono_add_internal_call ("System.Array::Set", ves_array_set);
4236 mono_add_internal_call ("System.Array::Get", ves_array_get);
4237 mono_add_internal_call ("System.Array::Address", ves_array_element_address);
4238 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
4239 ves_icall_get_frame_info);
4240 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",
4241 ves_icall_get_trace);
4242 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers", mono_runtime_install_handlers);
4244 metadata_section = &ms;
4245 InitializeCriticalSection (metadata_section);
4247 mono_jit_tls_id = TlsAlloc ();
4249 /* Don't set up the main thread for managed code execution -
4250 * this will give a handy assertion fail in
4251 * mono_get_lmf_addr() if any buggy runtime code tries to run
4252 * managed code in this thread.
4254 * Note, adding static initializer/objects to thread.cs will
4255 * also cause mon_get_lmf_addr assertion
4258 /* mono_thread_start_cb (GetCurrentThreadId (), (gpointer)-1, NULL); */
4260 mono_install_compile_method (mono_jit_compile_method);
4261 mono_install_trampoline (arch_create_jit_trampoline);
4262 mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline);
4263 mono_install_handler (arch_get_throw_exception ());
4264 mono_install_runtime_invoke (mono_jit_runtime_invoke);
4265 mono_install_stack_walk (mono_jit_walk_stack);
4266 mono_install_get_config_dir ();
4268 domain = mono_init (file);
4269 mono_runtime_init (domain, mono_thread_start_cb, mono_thread_attach_cb);
4275 mono_jit_cleanup (MonoDomain *domain)
4277 mono_domain_finalize (domain);
4279 mono_runtime_cleanup (domain);
4281 mono_debug_cleanup ();
4283 #ifdef PLATFORM_WIN32
4284 win32_seh_cleanup();
4287 mono_domain_unload (domain, TRUE);
4289 if (mono_jit_stats.enabled) {
4290 g_print ("Mono Jit statistics\n");
4291 g_print ("Compiled methods: %ld\n", mono_jit_stats.methods_compiled);
4292 g_print ("Methods cache lookup: %ld\n", mono_jit_stats.methods_lookups);
4293 g_print ("Method trampolines: %ld\n", mono_jit_stats.method_trampolines);
4294 g_print ("Basic blocks: %ld\n", mono_jit_stats.basic_blocks);
4295 g_print ("Max basic blocks: %ld\n", mono_jit_stats.max_basic_blocks);
4296 g_print ("Allocated vars: %ld\n", mono_jit_stats.allocate_var);
4297 g_print ("Analyze stack repeat: %ld\n", mono_jit_stats.analyze_stack_repeat);
4298 g_print ("Compiled CIL code size: %ld\n", mono_jit_stats.cil_code_size);
4299 g_print ("Native code size: %ld\n", mono_jit_stats.native_code_size);
4300 g_print ("Max code size ratio: %.2f (%s::%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
4301 mono_jit_stats.max_ratio_method->klass->name, mono_jit_stats.max_ratio_method->name);
4302 g_print ("Biggest method: %ld (%s::%s)\n", mono_jit_stats.biggest_method_size,
4303 mono_jit_stats.biggest_method->klass->name, mono_jit_stats.biggest_method->name);
4304 g_print ("Code reallocs: %ld\n", mono_jit_stats.code_reallocs);
4305 g_print ("Allocated code size: %ld\n", mono_jit_stats.allocated_code_size);
4306 g_print ("Inlineable methods: %ld\n", mono_jit_stats.inlineable_methods);
4307 g_print ("Inlined methods: %ld\n", mono_jit_stats.inlined_methods);
4309 g_print ("\nCreated object count: %ld\n", mono_stats.new_object_count);
4310 g_print ("Initialized classes: %ld\n", mono_stats.initialized_class_count);
4311 g_print ("Used classes: %ld\n", mono_stats.used_class_count);
4312 g_print ("Static data size: %ld\n", mono_stats.class_static_data_size);
4313 g_print ("VTable data size: %ld\n", mono_stats.class_vtable_size);
4316 DeleteCriticalSection (metadata_section);
4322 * @image: reference to an image
4323 * @verbose: If true, print debugging information on stdout.
4325 * JIT compilation of all methods in the image.
4328 mono_jit_compile_image (MonoImage *image, int verbose)
4331 MonoTableInfo *t = &image->tables [MONO_TABLE_METHOD];
4334 for (i = 0; i < t->rows; i++) {
4336 method = mono_get_method (image,
4337 (MONO_TABLE_METHOD << 24) | (i + 1),
4341 g_print ("Compiling: %s:%s\n\n", image->assembly_name, method->name);
4343 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT) {
4345 printf ("ABSTARCT\n");
4347 mono_compile_method (method);