2 * jit.c: The mono JIT compiler.
5 * Dietmar Maurer (dietmar@ximian.com)
7 * (C) 2001 Ximian, Inc.
20 #include <mono/metadata/verify.h>
21 #include <mono/metadata/assembly.h>
22 #include <mono/metadata/loader.h>
23 #include <mono/metadata/cil-coff.h>
24 #include <mono/metadata/tabledefs.h>
25 #include <mono/metadata/class.h>
26 #include <mono/metadata/object.h>
27 #include <mono/metadata/debug-helpers.h>
28 #include <mono/metadata/opcodes.h>
29 #include <mono/metadata/mono-endian.h>
30 #include <mono/metadata/tokentype.h>
31 #include <mono/metadata/threads.h>
32 #include <mono/metadata/socket-io.h>
33 #include <mono/metadata/appdomain.h>
34 #include <mono/arch/x86/x86-codegen.h>
35 #include <mono/io-layer/io-layer.h>
36 #include <mono/metadata/profiler-private.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;
218 gboolean mono_inline_memcpy = TRUE;
220 /* Use alternative (faster) sequence to convert FP values to integers */
221 gboolean mono_use_fast_iconv = FALSE;
223 /* TLS id to store jit data */
224 guint32 mono_jit_tls_id;
226 /* issue a breakpoint on unhandled excepions */
227 gboolean mono_break_on_exc = FALSE;
229 MonoDebugFormat mono_debug_format = MONO_DEBUG_FORMAT_NONE;
230 GList *mono_debug_methods = NULL;
232 /* If non-zero, insert a breakpoint when compiling the next method.
233 * If positive, interpret this variable as a counter and decrement
234 * it after setting the breakpoint. */
235 int mono_debug_insert_breakpoint = 0;
237 /* This is the address of the last breakpoint which was inserted. */
238 gchar *mono_debug_last_breakpoint_address = NULL;
240 MonoJitStats mono_jit_stats;
242 CRITICAL_SECTION *metadata_section = NULL;
245 * We sometimes need static data, for example the forest generator need it to
246 * store constants or class data.
248 inline static gpointer
249 mono_alloc_static (int size)
251 return g_malloc (size);
253 inline static gpointer
254 mono_alloc_static0 (int size)
256 return g_malloc0 (size);
259 typedef void (*MonoCCtor) (void);
262 mono_allocate_intvar (MonoFlowGraph *cfg, int slot, MonoValueType type)
264 int size, align, vnum, pos;
266 g_assert (type != VAL_UNKNOWN);
268 /* take care if you modify MonoValueType */
269 g_assert (VAL_DOUBLE == 4);
271 /* fixme: machine dependant */
272 if (type == VAL_POINTER)
273 type = VAL_I32; /* VAL_I32 and VAL_POINTER share the same slot */
275 pos = type - 1 + slot * VAL_DOUBLE;
277 if ((vnum = cfg->intvars [pos]))
279 mono_get_val_sizes (type, &size, &align);
281 cfg->intvars[pos] = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, type);
283 return cfg->intvars[pos];
287 mono_allocate_excvar (MonoFlowGraph *cfg)
292 cfg->excvar = arch_allocate_var (cfg, 4, 4, MONO_TEMPVAR, VAL_POINTER);
300 * @cfg: pointer to the control flow graph
301 * @type: the type of the value to load
302 * @addr: the address of the value
304 * Creates a tree to load the value at address @addr.
306 inline static MBTree *
307 ctree_create_load (MonoFlowGraph *cfg, MonoType *type, MBTree *addr, MonoValueType *svt, gboolean arg)
309 MonoMemPool *mp = cfg->mp;
314 ldind = mono_map_ldarg_type (type, svt);
316 ldind = mono_map_ldind_type (type, svt);
318 t = mono_ctree_new (mp, ldind, addr, NULL);
324 * ctree_create_store:
325 * @mp: pointer to a memory pool
326 * @addr_type: address type (MB_TERM_ADDR_L or MB_TERM_ADDR_G)
327 * @s: the value (tree) to store
328 * @type: the type of the value
329 * @addr: the address of the value
331 * Creates a tree to store the value @s at address @addr.
333 inline static MBTree *
334 ctree_create_store (MonoFlowGraph *cfg, MonoType *type, MBTree *addr,
335 MBTree *s, gboolean arg)
337 MonoMemPool *mp = cfg->mp;
342 stind = mono_map_starg_type (type);
344 stind = mono_map_stind_type (type);
346 t = mono_ctree_new (mp, stind, addr, s);
349 t->data.i = mono_class_value_size (type->data.klass, NULL);
354 inline static MBTree *
355 ctree_dup_address (MonoMemPool *mp, MBTree *s)
363 t = mono_ctree_new_leaf (mp, s->op);
364 t->data.i = s->data.i;
365 t->svt = VAL_POINTER;
368 g_warning ("unknown tree opcode %d", s->op);
369 g_assert_not_reached ();
376 * Create a duplicate of the value of a tree. This is
377 * easy for trees starting with LDIND/STIND, since the
378 * duplicate is simple a LDIND tree with the same address.
379 * For other trees we have to split the tree into one tree
380 * storing the value to a new temporary variable, and
381 * another tree which loads that value back. We can then
382 * duplicate the second tree.
385 ctree_create_dup (MonoMemPool *mp, MBTree *s)
390 case MB_TERM_STIND_I1:
391 case MB_TERM_LDIND_I1:
392 t = ctree_dup_address (mp, s->left);
393 t = mono_ctree_new (mp, MB_TERM_LDIND_I1, t, NULL);
396 case MB_TERM_STIND_I2:
397 case MB_TERM_LDIND_I2:
398 t = ctree_dup_address (mp, s->left);
399 t = mono_ctree_new (mp, MB_TERM_LDIND_I2, t, NULL);
402 case MB_TERM_STIND_I4:
403 case MB_TERM_LDIND_I4:
404 t = ctree_dup_address (mp, s->left);
405 t = mono_ctree_new (mp, MB_TERM_LDIND_I4, t, NULL);
408 case MB_TERM_STIND_I8:
409 case MB_TERM_LDIND_I8:
410 t = ctree_dup_address (mp, s->left);
411 t = mono_ctree_new (mp, MB_TERM_LDIND_I8, t, NULL);
414 case MB_TERM_STIND_R4:
415 case MB_TERM_LDIND_R4:
416 t = ctree_dup_address (mp, s->left);
417 t = mono_ctree_new (mp, MB_TERM_LDIND_R4, t, NULL);
420 case MB_TERM_STIND_R8:
421 case MB_TERM_LDIND_R8:
422 t = ctree_dup_address (mp, s->left);
423 t = mono_ctree_new (mp, MB_TERM_LDIND_R8, t, NULL);
427 g_warning ("unknown op \"%s\"", mono_burg_term_string [s->op]);
428 g_assert_not_reached ();
435 mono_store_tree (MonoFlowGraph *cfg, int slot, MBTree *s, MBTree **tdup)
437 MonoMemPool *mp = cfg->mp;
442 case MB_TERM_STIND_I1:
443 case MB_TERM_LDIND_I1:
444 case MB_TERM_STIND_I2:
445 case MB_TERM_LDIND_I2:
446 case MB_TERM_STIND_I4:
447 case MB_TERM_LDIND_I4:
448 case MB_TERM_STIND_I8:
449 case MB_TERM_LDIND_I8:
450 case MB_TERM_STIND_R4:
451 case MB_TERM_LDIND_R4:
452 case MB_TERM_STIND_R8:
453 case MB_TERM_LDIND_R8: {
455 vnum = mono_allocate_intvar (cfg, slot, s->svt);
457 if (s->left->op == MB_TERM_ADDR_L && s->left->data.i == vnum) {
459 *tdup = ctree_create_dup (mp, s);
465 *tdup = ctree_create_dup (mp, s);
470 g_assert (s->svt != VAL_UNKNOWN);
473 vnum = mono_allocate_intvar (cfg, slot, s->svt);
476 mono_get_val_sizes (s->svt, &size, &align);
477 vnum = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, s->svt);
480 t = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
483 t = mono_ctree_new (mp, mono_map_store_svt_type (s->svt), t, s);
489 mono_store_tree (cfg, -1, t, tdup);
495 mono_find_final_block (MonoFlowGraph *cfg, guint32 ip, guint32 target, int type)
497 MonoMethod *method = cfg->method;
498 MonoBytecodeInfo *bcinfo = cfg->bcinfo;
499 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
500 MonoExceptionClause *clause;
503 for (i = 0; i < header->num_clauses; ++i) {
504 clause = &header->clauses [i];
506 if (MONO_OFFSET_IN_CLAUSE (clause, ip) &&
507 (!MONO_OFFSET_IN_CLAUSE (clause, target))) {
508 if (clause->flags & type) {
509 g_assert (bcinfo [clause->handler_offset].is_block_start);
510 return &cfg->bblocks [bcinfo [clause->handler_offset].block_id];
518 mono_cfg_add_successor (MonoFlowGraph *cfg, MonoBBlock *bb, gint32 target)
523 g_assert (cfg->bcinfo [target].is_block_start);
525 tbb = &cfg->bblocks [cfg->bcinfo [target].block_id];
528 for (l = bb->succ; l; l = l->next) {
529 MonoBBlock *t = (MonoBBlock *)l->data;
534 bb->succ = g_list_prepend (bb->succ, tbb);
538 #define CREATE_BLOCK(t) {if (!bcinfo [t].is_block_start) {block_count++;bcinfo [t].is_block_start = 1; }}
541 mono_analyze_flow (MonoFlowGraph *cfg)
543 MonoMethod *method = cfg->method;
544 register const unsigned char *ip, *end;
545 MonoMethodHeader *header;
546 MonoBytecodeInfo *bcinfo;
547 MonoExceptionClause *clause;
548 MonoBBlock *bblocks, *bb;
549 const MonoOpcode *opcode;
553 header = ((MonoMethodNormal *)method)->header;
555 bcinfo = g_malloc0 (header->code_size * sizeof (MonoBytecodeInfo));
556 bcinfo [0].is_block_start = 1;
561 end = ip + header->code_size;
563 mono_jit_stats.cil_code_size += header->code_size;
565 /* fixme: add block boundaries for exceptions */
566 for (i = 0; i < header->num_clauses; ++i) {
567 clause = &header->clauses [i];
568 CREATE_BLOCK (clause->try_offset);
569 CREATE_BLOCK (clause->handler_offset);
573 guint32 cli_addr = ip - header->code;
575 //printf ("IL%04x OPCODE %s\n", cli_addr, mono_opcode_names [*ip]);
578 CREATE_BLOCK (cli_addr);
589 opcode = &mono_opcodes [i];
591 switch (opcode->flow_type) {
592 case MONO_FLOW_RETURN:
593 case MONO_FLOW_ERROR:
596 case MONO_FLOW_BRANCH: /* we handle branch when checking the argument type */
597 case MONO_FLOW_COND_BRANCH:
603 g_assert_not_reached ();
606 switch (opcode->argument) {
610 case MonoInlineString:
611 mono_ldstr (mono_domain_get (), method->klass->image, mono_metadata_token_index (read32 (ip + 1)));
614 case MonoInlineField:
615 case MonoInlineMethod:
618 case MonoShortInlineR:
625 case MonoShortInlineVar:
626 case MonoShortInlineI:
629 case MonoShortInlineBrTarget:
631 i = (signed char)*ip;
633 CREATE_BLOCK (cli_addr + 2 + i);
637 case MonoInlineBrTarget:
641 CREATE_BLOCK (cli_addr + 5 + i);
644 case MonoInlineSwitch: {
645 gint32 st, target, n;
649 st = cli_addr + 5 + 4 * n;
652 for (i = 0; i < n; i++) {
653 target = read32 (ip) + st;
655 CREATE_BLOCK (target);
658 * Note: the code didn't set block_end in switch.
667 g_assert_not_reached ();
672 g_assert (block_count);
674 bb = bblocks = g_malloc0 (sizeof (MonoBBlock) * block_count);
677 bblocks [0].reached = 1;
679 for (i = 0; i < header->code_size; i++) {
680 if (bcinfo [i].is_block_start) {
682 bb->num = block_count;
683 bb->forest = g_ptr_array_new ();
685 bb [-1].length = i - bb [-1].cli_addr;
686 bcinfo [i].block_id = block_count;
691 bb [-1].length = header->code_size - bb [-1].cli_addr;
693 cfg->bcinfo = bcinfo;
694 cfg->bblocks = bblocks;
695 cfg->block_count = block_count;
697 mono_jit_stats.basic_blocks += block_count;
698 mono_jit_stats.max_basic_blocks = MAX (block_count, mono_jit_stats.max_basic_blocks);
700 for (i = 0; i < header->num_clauses; ++i) {
701 MonoBBlock *sbb, *tbb;
702 clause = &header->clauses [i];
703 sbb = &cfg->bblocks [bcinfo [clause->try_offset].block_id];
704 tbb = &cfg->bblocks [bcinfo [clause->handler_offset].block_id];
705 g_assert (sbb && tbb);
706 sbb->succ = g_list_prepend (sbb->succ, tbb);
710 end = ip + header->code_size;
714 guint32 cli_addr = ip - header->code;
716 if (bcinfo [cli_addr].is_block_start) {
717 MonoBBlock *tbb = &cfg->bblocks [bcinfo [cli_addr].block_id];
719 bb->succ = g_list_prepend (bb->succ, tbb);
731 opcode = &mono_opcodes [i];
733 switch (opcode->argument) {
737 case MonoInlineString:
739 case MonoInlineField:
740 case MonoInlineMethod:
743 case MonoShortInlineR:
750 case MonoShortInlineVar:
751 case MonoShortInlineI:
754 case MonoShortInlineBrTarget:
756 i = (signed char)*ip;
758 mono_cfg_add_successor (cfg, bb, cli_addr + 2 + i);
759 if (opcode->flow_type == MONO_FLOW_COND_BRANCH)
760 mono_cfg_add_successor (cfg, bb, cli_addr + 2);
762 case MonoInlineBrTarget:
766 mono_cfg_add_successor (cfg, bb, cli_addr + 5 + i);
767 if (opcode->flow_type == MONO_FLOW_COND_BRANCH)
768 mono_cfg_add_successor (cfg, bb, cli_addr + 5);
770 case MonoInlineSwitch: {
771 gint32 st, target, n;
775 st = cli_addr + 5 + 4 * n;
776 mono_cfg_add_successor (cfg, bb, st);
778 for (i = 0; i < n; i++) {
779 target = read32 (ip) + st;
781 mono_cfg_add_successor (cfg, bb, target);
790 g_assert_not_reached ();
796 * ves_array_element_address:
797 * @this: a pointer to the array object
799 * Returns: the address of an array element.
802 ves_array_element_address (MonoArray *this, ...)
809 g_assert (this != NULL);
813 class = this->obj.vtable->klass;
815 ind = va_arg(ap, int);
816 if (this->bounds != NULL) {
817 ind -= this->bounds [0].lower_bound;
818 for (i = 1; i < class->rank; i++) {
819 ind = ind*this->bounds [i].length + va_arg(ap, int) -
820 this->bounds [i].lower_bound;;
824 esize = mono_array_element_size (class);
825 ea = (gpointer*)((char*)this->vector + (ind * esize));
826 //printf ("AADDRESS %p %p %d\n", this, ea, ind);
834 mono_array_new_va (MonoMethod *cm, ...)
836 MonoDomain *domain = mono_domain_get ();
839 guint32 *lower_bounds;
840 int pcount = cm->signature->param_count;
841 int rank = cm->klass->rank;
846 lengths = alloca (sizeof (guint32) * pcount);
847 for (i = 0; i < pcount; ++i)
848 lengths [i] = d = va_arg(ap, int);
850 if (rank == pcount) {
851 /* Only lengths provided. */
854 g_assert (pcount == (rank * 2));
855 /* lower bounds are first. */
856 lower_bounds = lengths;
861 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
864 #define ADD_TREE(t,a) do { t->cli_addr = a; g_ptr_array_add (forest, (t)); } while (0)
865 #define PUSH_TREE(t,k) do { int tt = k; *sp = t; t->svt = tt; sp++; } while (0)
867 #define LOCAL_POS(n) (1 + n)
870 #define LOCAL_TYPE(n) ((header)->locals [(n)]->type == MONO_TYPE_BOOLEAN && !(header)->locals [(n)]->byref ? &mono_defaults.int32_class->byval_arg : (header)->locals [(n)])
872 #define LOCAL_TYPE(n) ((header)->locals [(n)])
875 #define ARG_POS(n) (firstarg + n)
876 #define ARG_TYPE(n) ((n) ? (signature)->params [(n) - (signature)->hasthis] : \
877 (signature)->hasthis ? &method->klass->this_arg: (signature)->params [(0)])
881 * replaces all occurences of variable @varnum in @tree with @copy.
884 mono_copy_used_var (MonoFlowGraph *cfg, MBTree *tree, int varnum, MBTree **copy)
890 mono_copy_used_var (cfg, tree->left, varnum, copy);
892 mono_copy_used_var (cfg, tree->right, varnum, copy);
895 case MB_TERM_LDIND_I1:
896 case MB_TERM_LDIND_I2:
897 case MB_TERM_LDIND_I4:
898 case MB_TERM_LDIND_I8:
899 case MB_TERM_LDIND_R4:
900 case MB_TERM_LDIND_R8:
901 if (tree->left->op == MB_TERM_ADDR_L &&
902 tree->left->data.i == varnum) {
904 tree->left->data.i = (*copy)->left->data.i;
908 mono_get_val_sizes (tree->svt, &size, &align);
909 v = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, tree->svt);
911 t1 = mono_ctree_new_leaf (cfg->mp, MB_TERM_ADDR_L);
914 t2 = mono_ctree_new_leaf (cfg->mp, MB_TERM_ADDR_L);
916 t2 = mono_ctree_new (cfg->mp, tree->op, t2, NULL);
918 t2 = mono_ctree_new (cfg->mp, mono_map_store_svt_type (tree->svt), t1, t2);
921 tree->left->data.i = v;
929 * if a variable is modified and there are still referencence
930 * to it on the runtime stack we need to store the value into
931 * a temporary variable and use that value instead of the
935 mono_stack_duplicate_used_var (MonoFlowGraph *cfg, MBTree **stack, MBTree **sp, int varnum)
940 mono_copy_used_var (cfg, *stack, varnum, &res);
948 check_inlining (MonoMethod *method)
950 MonoMethodHeader *header;
951 MonoMethodSignature *signature = method->signature;
952 register const unsigned char *ip, *end;
954 int i, arg_used [256];
958 if (method->inline_info)
959 return method->inline_count;
961 method->inline_info = 1;
963 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
964 (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
965 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
966 (method->klass->marshalbyref) ||
967 ISSTRUCT (signature->ret))
970 if (!(header = ((MonoMethodNormal *)method)->header) ||
974 if (header->num_clauses)
978 end = ip + header->code_size;
980 for (i = 0; i < 256; i++)
984 while (!stop && ip < end) {
1033 case CEE_CONV_OVF_I1_UN:
1034 case CEE_CONV_OVF_I2_UN:
1035 case CEE_CONV_OVF_I4_UN:
1036 case CEE_CONV_OVF_I8_UN:
1037 case CEE_CONV_OVF_U1_UN:
1038 case CEE_CONV_OVF_U2_UN:
1039 case CEE_CONV_OVF_U4_UN:
1040 case CEE_CONV_OVF_U8_UN:
1041 case CEE_CONV_OVF_I_UN:
1042 case CEE_CONV_OVF_U_UN:
1054 case CEE_LDELEM_REF:
1062 case CEE_STELEM_REF:
1063 case CEE_CONV_OVF_I1:
1064 case CEE_CONV_OVF_U1:
1065 case CEE_CONV_OVF_I2:
1066 case CEE_CONV_OVF_U2:
1067 case CEE_CONV_OVF_I4:
1068 case CEE_CONV_OVF_U4:
1069 case CEE_CONV_OVF_I8:
1070 case CEE_CONV_OVF_U8:
1075 case CEE_CONV_OVF_I:
1076 case CEE_CONV_OVF_U:
1078 case CEE_ADD_OVF_UN:
1080 case CEE_MUL_OVF_UN:
1082 case CEE_SUB_OVF_UN:
1128 case CEE_CALLVIRT: {
1132 token = read32 (ip);
1135 cm = mono_get_method (method->klass->image, token, NULL);
1147 int an = (*ip) - CEE_LDARG_0;
1150 arg_used [an] = TRUE;
1158 arg_used [*ip] = TRUE;
1170 if (an > 255 || arg_used [an])
1172 arg_used [an] = TRUE;
1186 case CEE_LDVIRTFTN: {
1190 token = read32 (ip);
1193 cm = mono_get_method (method->klass->image, token, NULL);
1217 !(ip [0] == CEE_RET ||
1219 ip [0] == CEE_STLOC_0 &&
1220 ip [1] == CEE_BR_S &&
1222 ip [3] == CEE_LDLOC_0 &&
1223 ip [4] == CEE_RET)))
1226 if (signature->hasthis && arg_used [0])
1227 method->uses_this = 1;
1229 mono_jit_stats.inlineable_methods++;
1231 return method->inline_count = ip - header->code;
1234 return method->inline_count = -1;
1238 create_outstack (MonoFlowGraph *cfg, MonoBBlock *bb, MBTree **stack, int depth)
1240 MonoMemPool *mp = cfg->mp;
1241 MBTree **c = stack, *t1, *t2;
1242 GPtrArray *forest = bb->forest;
1245 g_assert (bb->reached);
1251 g_assert (bb->outdepth == depth);
1255 bb->outdepth = depth;
1256 bb->outstack = mono_mempool_alloc (mp, depth * sizeof (MBTree *));
1258 for (i = 0; i < depth; i++) {
1259 if ((t1 = mono_store_tree (cfg, i, c [i], &t2)))
1261 bb->outstack [i] = t2;
1266 mark_reached (MonoFlowGraph *cfg, MonoBBlock *target, MBTree **stack, int depth)
1268 MonoMemPool *mp = cfg->mp;
1271 if (target->reached)
1274 target->reached = 1;
1281 if (target->instack) {
1282 g_assert (target->indepth == depth);
1286 target->indepth = depth;
1287 target->instack = mono_mempool_alloc (mp, depth * sizeof (MBTree *));
1289 for (i = 0; i < depth; i++) {
1290 target->instack [i] = ctree_create_dup (mp, stack [i]);
1296 #define MARK_REACHED(bb) do { if (!bb->reached) { bb->reached = 1; }} while (0)
1299 * mono_analyze_stack:
1300 * @cfg: control flow graph
1302 * This is the architecture independent part of JIT compilation.
1303 * It creates a forest of trees which can then be fed into the
1304 * architecture dependent code generation.
1306 * The algorithm is from Andi Krall, the same is used in CACAO
1309 mono_analyze_stack (MonoFlowGraph *cfg)
1311 MonoMethod *method = cfg->method;
1312 MonoMemPool *mp = cfg->mp;
1313 MonoBytecodeInfo *bcinfo = cfg->bcinfo;
1314 MonoMethodHeader *header;
1315 MonoMethodSignature *signature;
1318 MBTree **sp, **stack, **arg_sp, **arg_map = NULL, *t1, *t2, *t3;
1319 register const unsigned char *ip, *end;
1321 int i, j, depth, repeat_count;
1322 int varnum = 0, firstarg = 0, retvtarg = 0;
1323 gboolean repeat, superblock_end;
1324 MonoBBlock *bb, *tbb;
1326 GList *inline_list = NULL;
1328 header = ((MonoMethodNormal *)method)->header;
1329 signature = method->signature;
1330 image = method->klass->image;
1332 /* we add 10 extra slots for method inlining */
1333 maxstack = header->max_stack + 10;
1334 sp = stack = alloca (sizeof (MBTree *) * (maxstack + 1));
1336 if (header->num_locals) {
1339 for (i = 0; i < header->num_locals; ++i) {
1341 size = mono_type_size (LOCAL_TYPE (i), &align);
1342 mono_map_ldind_type (header->locals [i], &svt);
1343 varnum = arch_allocate_var (cfg, size, align, MONO_LOCALVAR, svt);
1345 cfg->locals_start_index = varnum;
1349 if (ISSTRUCT (signature->ret)) {
1354 size = mono_type_size (signature->ret, &align);
1356 retvtarg = varnum = arch_allocate_var (cfg, size, align, MONO_LOCALVAR, VAL_UNKNOWN);
1358 //printf ("VALUETYPE METHOD %s.%s::%s %d\n", method->klass->name_space,
1359 //method->klass->name, method->name, size);
1362 cfg->args_start_index = firstarg = varnum + 1;
1364 if (signature->hasthis) {
1366 thisvar = arch_allocate_var (cfg, sizeof (gpointer), sizeof (gpointer), MONO_ARGVAR, VAL_POINTER);
1367 VARINFO (cfg, thisvar).isvolatile = 1;
1370 if (signature->param_count) {
1373 for (i = 0; i < signature->param_count; ++i) {
1375 size = mono_type_stack_size (signature->params [i], &align);
1376 argvar = arch_allocate_var (cfg, size, align, MONO_ARGVAR, VAL_UNKNOWN);
1377 VARINFO (cfg, argvar).isvolatile = 1;
1381 for (i = 0; i < header->num_clauses; ++i) {
1382 MonoExceptionClause *clause = &header->clauses [i];
1383 tbb = &cfg->bblocks [bcinfo [clause->handler_offset].block_id];
1384 if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) {
1385 tbb->instack = mono_mempool_alloc (mp, sizeof (MBTree *));
1387 tbb->instack [0] = t1 = mono_ctree_new_leaf (mp, MB_TERM_EXCEPTION);
1388 t1->data.i = mono_allocate_excvar (cfg);
1389 t1->svt = VAL_POINTER;
1391 } else if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
1392 mark_reached (cfg, tbb, NULL, 0);
1394 g_warning ("implement me");
1395 g_assert_not_reached ();
1403 superblock_end = TRUE;
1406 //printf ("START\n");
1407 for (i = 0; i < cfg->block_count; i++) {
1408 bb = &cfg->bblocks [i];
1410 //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);
1412 if (!bb->reached && !superblock_end) {
1413 MonoBBlock *sbb = &cfg->bblocks [i - 1];
1415 g_assert (sbb->outdepth == (sp - stack));
1417 mark_reached (cfg, bb, sbb->outstack, sbb->outdepth);
1422 if (!bb->finished) {
1426 for (j = 0; j < bb->indepth; j++) {
1427 sp [j] = bb->instack [j];
1433 ip = header->code + bb->cli_addr;
1434 end = ip + bb->length;
1436 forest = bb->forest;
1438 superblock_end = FALSE;
1441 while (inline_list || ip < end) {
1445 MonoInlineInfo *ii = (MonoInlineInfo *)inline_list->data;
1446 if (ip >= ii->end) {
1447 inline_list = g_list_remove_link (inline_list, inline_list);
1449 image = ii->saved_image;
1451 arg_map = ((MonoInlineInfo *)inline_list->data)->arg_map;
1457 cli_addr = ip - header->code;
1460 //if (inline_list) printf ("INLINE IL%04x OPCODE %s\n", cli_addr, mono_opcode_names [*ip]);
1462 //printf ("%d IL%04x OPCODE %s %d %d %d\n", i, cli_addr, mono_opcode_names [*ip],
1463 //forest->len, superblock_end, sp - stack);
1470 t1 = mono_ctree_new (mp, MB_TERM_THROW, *sp, NULL);
1471 ADD_TREE (t1, cli_addr);
1472 superblock_end = TRUE;
1481 token = read32 (ip);
1484 c = mono_class_get (image, token);
1486 t1 = mono_ctree_new_leaf (mp, MB_TERM_NEWOBJ);
1488 t1->svt = VAL_POINTER;
1490 t1 = mono_store_tree (cfg, -1, t1, &t3);
1492 ADD_TREE (t1, cli_addr);
1494 t1 = ctree_create_dup (mp, t3);
1495 t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1496 t2->data.i = sizeof (MonoObject);
1497 t1 = mono_ctree_new (mp, MB_TERM_ADD, t1, t2);
1499 t1 = ctree_create_store (cfg, &c->byval_arg, t1, *sp, FALSE);
1500 ADD_TREE (t1, cli_addr);
1502 PUSH_TREE (t3, VAL_POINTER);
1511 token = read32 (ip);
1515 class = mono_class_get (image, token);
1516 t1 = mono_ctree_new (mp, MB_TERM_UNBOX, *sp, NULL);
1517 t1->data.klass = class;
1519 PUSH_TREE (t1, VAL_POINTER);
1526 t1 = mono_ctree_new (mp, MB_TERM_LDLEN, *sp, NULL);
1527 PUSH_TREE (t1, VAL_I32);
1536 token = read32 (ip);
1540 c = mono_class_get (image, token);
1541 g_assert (c->valuetype);
1543 t1 = ctree_create_load (cfg, &c->byval_arg, *sp, &svt, FALSE);
1544 PUSH_TREE (t1, svt);
1553 token = read32 (ip);
1557 c = mono_class_get (image, token);
1558 g_assert (c->valuetype);
1560 size = mono_class_value_size (c, NULL);
1562 t1 = mono_ctree_new (mp, MB_TERM_STIND_OBJ, sp [0], sp [1]);
1564 ADD_TREE (t1, cli_addr);
1572 ind = mono_metadata_token_index (read32 (ip));
1575 if (cfg->share_code) {
1576 t1 = mono_ctree_new_leaf (mp, MB_TERM_LDSTR);
1579 o = (MonoObject *) mono_ldstr (cfg->domain, image, ind);
1580 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1584 PUSH_TREE (t1, VAL_POINTER);
1590 MonoClassField *field;
1592 int load_addr = *ip == CEE_LDSFLDA;
1595 token = read32 (ip);
1598 /* need to handle fieldrefs */
1599 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
1600 field = mono_field_from_memberref (image, token, &klass);
1601 mono_class_init (klass);
1603 klass = mono_class_get (image,
1604 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
1605 mono_class_init (klass);
1606 field = mono_class_get_field (klass, token);
1611 if (cfg->share_code) {
1612 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1613 t1->data.i = field->offset;
1614 t1 = mono_ctree_new (mp, MB_TERM_LDSFLDA, t1, NULL);
1615 t1->data.klass = klass;
1617 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
1618 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
1619 t1->data.p = (char*)(vt->data) + field->offset;
1625 t1 = ctree_create_load (cfg, field->type, t1, &svt, FALSE);
1628 PUSH_TREE (t1, svt);
1634 MonoClassField *field;
1636 int load_addr = *ip == CEE_LDFLDA;
1639 token = read32 (ip);
1643 /* need to handle fieldrefs */
1644 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
1645 field = mono_field_from_memberref (image, token, &klass);
1646 mono_class_init (klass);
1648 klass = mono_class_get (image,
1649 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
1650 mono_class_init (klass);
1651 field = mono_class_get_field (klass, token);
1655 if (klass->marshalbyref) {
1656 t1 = mono_ctree_new (mp, MB_TERM_REMOTE_LDFLDA, sp [0], NULL);
1657 t1->data.fi.klass = klass;
1658 t1->data.fi.field = field;
1660 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1662 if (klass->valuetype)
1663 t1->data.i = field->offset - sizeof (MonoObject);
1665 t1->data.i = field->offset;
1667 t1 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], t1);
1671 t1 = ctree_create_load (cfg, field->type, t1, &svt, FALSE);
1675 PUSH_TREE (t1, svt);
1680 MonoClassField *field;
1684 token = read32 (ip);
1688 /* need to handle fieldrefs */
1689 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
1690 field = mono_field_from_memberref (image, token, &klass);
1691 mono_class_init (klass);
1693 klass = mono_class_get (image,
1694 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
1695 mono_class_init (klass);
1696 field = mono_class_get_field (klass, token);
1701 if (cfg->share_code) {
1702 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1703 t1->data.i = field->offset;
1704 t1 = mono_ctree_new (mp, MB_TERM_LDSFLDA, t1, NULL);
1705 t1->data.klass = klass;
1707 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
1708 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
1709 t1->data.p = (char*)(vt->data) + field->offset;
1711 t1 = ctree_create_store (cfg, field->type, t1, *sp, FALSE);
1713 ADD_TREE (t1, cli_addr);
1718 MonoClassField *field;
1722 token = read32 (ip);
1726 /* need to handle fieldrefs */
1727 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
1728 field = mono_field_from_memberref (image, token, &klass);
1729 mono_class_init (klass);
1731 klass = mono_class_get (image,
1732 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
1733 mono_class_init (klass);
1734 field = mono_class_get_field (klass, token);
1738 if (klass->marshalbyref) {
1739 t1 = mono_ctree_new (mp, mono_map_remote_stind_type (field->type), sp [0], sp [1]);
1740 t1->data.fi.klass = klass;
1741 t1->data.fi.field = field;
1743 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1744 t1->data.i = klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset;
1745 t1 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], t1);
1746 t1 = ctree_create_store (cfg, field->type, t1, sp [1], FALSE);
1750 ADD_TREE (t1, cli_addr);
1755 guint32 esize, token;
1758 token = read32 (ip);
1762 class = mono_class_get (image, token);
1764 mono_class_init (class);
1766 esize = mono_class_instance_size (class);
1767 if (class->valuetype)
1768 esize -= sizeof (MonoObject);
1770 t1 = mono_ctree_new (mp, MB_TERM_LDELEMA, sp [0], sp [1]);
1772 PUSH_TREE (t1, VAL_POINTER);
1781 t1 = mono_ctree_new_leaf (mp, MB_TERM_BREAK);
1782 ADD_TREE (t1, cli_addr);
1795 t1 = mono_ctree_new (mp, MB_TERM_SWITCH, *sp, NULL);
1796 jt = t1->data.p = mono_alloc_static (sizeof (gpointer) * (n + 2));
1797 st = cli_addr + 5 + 4 * n;
1799 // hack: we store n at position 0
1800 jt [0] = (MonoBBlock *)n;
1802 create_outstack (cfg, bb, stack, sp - stack);
1804 for (k = 1; k <= (n + 1); k++) {
1808 target = read32 (ip) + st;
1811 g_assert (target >= 0 && target <= header->code_size);
1812 g_assert (bcinfo [target].is_block_start);
1813 tbb = &cfg->bblocks [bcinfo [target].block_id];
1814 mark_reached (cfg, tbb, stack, sp - stack);
1818 ADD_TREE (t1, cli_addr);
1823 MonoClass *handle_class;
1826 handle = mono_ldtoken (image, read32 (ip), &handle_class);
1829 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1830 t1->data.p = handle;
1831 PUSH_TREE (t1, VAL_POINTER);
1841 token = read32 (ip);
1842 class = mono_class_get (image, token);
1845 if (cfg->share_code) {
1846 t1 = mono_ctree_new (mp, MB_TERM_NEWARR, *sp, NULL);
1850 MonoClass *ac = mono_array_class_get (&class->byval_arg, 1);
1851 MonoVTable *vt = mono_class_vtable (cfg->domain, ac);
1853 t1 = mono_ctree_new (mp, MB_TERM_NEWARR_SPEC, *sp, NULL);
1857 PUSH_TREE (t1, VAL_POINTER);
1865 token = read32 (ip);
1866 class = mono_class_get (image, token);
1870 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1871 t1->data.i = mono_class_value_size (class, NULL);
1872 t1 = mono_ctree_new (mp, MB_TERM_CPSRC, sp [1], t1);
1873 t1 = mono_ctree_new (mp, MB_TERM_CPBLK, sp [0], t1);
1874 ADD_TREE (t1, cli_addr);
1879 MonoMethodSignature *csig;
1881 MBTree *this = NULL;
1883 int k, align, size, args_size = 0;
1888 token = read32 (ip);
1891 cm = mono_get_method (image, token, NULL);
1893 g_assert (!strcmp (cm->name, ".ctor"));
1895 csig = cm->signature;
1896 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
1897 g_assert (csig->hasthis);
1899 arg_sp = sp -= csig->param_count;
1901 if (!cm->klass->inited)
1902 mono_class_init (cm->klass);
1904 if (cm->klass->parent == mono_defaults.array_class) {
1906 this = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1908 } else if (cm->klass == mono_defaults.string_class) {
1910 this = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1913 if (cm->klass->valuetype) {
1914 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1915 t1->data.i = mono_class_value_size (cm->klass, NULL);
1916 this = mono_ctree_new (mp, MB_TERM_LOCALLOC, t1, NULL);
1917 this->data.i = TRUE;
1918 } else if (cfg->share_code) {
1919 this = mono_ctree_new_leaf (mp, MB_TERM_NEWOBJ);
1920 this->data.klass = cm->klass;
1922 MonoVTable *vt = mono_class_vtable (cfg->domain, cm->klass);
1923 this = mono_ctree_new_leaf (mp, MB_TERM_NEWOBJ_SPEC);
1927 this->svt = VAL_POINTER;
1929 t1 = mono_store_tree (cfg, -1, this, &this);
1931 ADD_TREE (t1, cli_addr);
1934 args_size += sizeof (gpointer); /* this argument */
1936 for (k = csig->param_count - 1; k >= 0; k--) {
1937 MonoType *type = cm->signature->params [k];
1939 size = mono_type_stack_size (type, &align);
1940 t1 = mono_ctree_new (mp, mono_map_arg_type (type), arg_sp [k], NULL);
1942 ADD_TREE (t1, cli_addr);
1947 if (newarr || newstr) {
1949 t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1951 t2->data.p = mono_array_new_va;
1953 t2->data.p = arch_create_jit_trampoline (cm);
1956 t1 = mono_ctree_new (mp, MB_TERM_CALL_I4, this, t2);
1957 t1->data.ci.args_size = args_size;
1958 t1->data.ci.vtype_num = 0;
1960 t1->svt = VAL_POINTER;
1962 t1 = mono_store_tree (cfg, -1, t1, &t2);
1964 ADD_TREE (t1, cli_addr);
1965 PUSH_TREE (t2, t2->svt);
1969 t2 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
1970 t2->data.p = arch_create_jit_trampoline (cm);
1972 t1 = mono_ctree_new (mp, mono_map_call_type (csig->ret, &svt), this, t2);
1973 t1->data.ci.args_size = args_size;
1974 t1->data.ci.vtype_num = 0;
1977 ADD_TREE (t1, cli_addr);
1979 t1 = ctree_create_dup (mp, this);
1981 if (cm->klass->valuetype) {
1982 t2 = ctree_create_load (cfg, &cm->klass->byval_arg, t1, &svt, FALSE);
1983 PUSH_TREE (t2, svt);
1985 PUSH_TREE (t1, t1->svt);
1992 case CEE_CALLVIRT: {
1993 MonoMethodSignature *csig;
1995 MBTree *ftn, *this = NULL;
1997 int k, align, size, args_size = 0;
1998 int virtual = *ip == CEE_CALLVIRT;
1999 int calli = *ip == CEE_CALLI;
2000 gboolean array_set = FALSE;
2001 gboolean array_get = FALSE;
2002 /* fixme: compute this value */
2003 gboolean shared_to_unshared_call = FALSE;
2004 int nargs, vtype_num = 0;
2007 token = read32 (ip);
2012 csig = mono_metadata_parse_signature (image, token);
2014 arg_sp = sp -= csig->param_count;
2016 cm = mono_get_method (image, token, NULL);
2019 if (cm->klass == mono_defaults.math_class &&
2020 cm->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
2022 if (!strcmp (cm->name, "Sin")) {
2024 t1 = mono_ctree_new (mp, MB_TERM_SIN, *sp, NULL);
2025 PUSH_TREE (t1, VAL_DOUBLE);
2027 } else if (!strcmp (cm->name, "Cos")) {
2029 t1 = mono_ctree_new (mp, MB_TERM_COS, *sp, NULL);
2030 PUSH_TREE (t1, VAL_DOUBLE);
2032 } else if (!strcmp (cm->name, "Sqrt")) {
2034 t1 = mono_ctree_new (mp, MB_TERM_SQRT, *sp, NULL);
2035 PUSH_TREE (t1, VAL_DOUBLE);
2040 if (cm->klass == mono_defaults.string_class &&
2041 *cm->name == '.' && !strcmp (cm->name, ".ctor"))
2042 g_assert_not_reached ();
2043 arg_sp = sp -= cm->signature->param_count;
2045 if ((cm->flags & METHOD_ATTRIBUTE_FINAL &&
2046 cm->klass != mono_defaults.object_class) ||
2047 !(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
2051 if (!calli && mono_jit_inline_code && !virtual && cm->inline_count != -1 &&
2052 (cm->inline_info || check_inlining (cm) >= 0)) {
2053 MonoInlineInfo *ii = alloca (sizeof (MonoInlineInfo));
2056 mono_jit_stats.inlined_methods++;
2058 if (cm->signature->hasthis)
2061 args = cm->signature->param_count + cm->signature->hasthis;
2065 ii->saved_image = image;
2066 ii->arg_map = alloca (args * sizeof (MBTree *));
2067 memcpy (ii->arg_map, sp, args * sizeof (MBTree *));
2069 if (cm->signature->hasthis && !cm->uses_this &&
2070 (ii->arg_map [0]->op != MB_TERM_CHECKTHIS)) {
2071 ii->arg_map [0] = mono_ctree_new (mp, MB_TERM_CHECKTHIS,
2072 ii->arg_map [0], NULL);
2073 ADD_TREE (ii->arg_map [0], cli_addr);
2076 if (cm->inline_count) {
2077 inline_list = g_list_prepend (inline_list, ii);
2078 ip = ((MonoMethodNormal *)cm)->header->code;
2079 ii->end = ip + cm->inline_count;
2080 arg_map = ii->arg_map;
2081 image = cm->klass->image;
2087 csig = cm->signature;
2089 nargs = csig->param_count;
2090 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
2091 g_assert (!virtual || csig->hasthis);
2093 if (!calli && cm->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
2094 if (cm->klass->parent == mono_defaults.array_class) {
2095 if (!strcmp (cm->name, "Set")) {
2098 } else if (!strcmp (cm->name, "Get"))
2103 for (k = nargs - 1; k >= 0; k--) {
2104 MonoType *type = csig->params [k];
2105 t1 = mono_ctree_new (mp, mono_map_arg_type (type), arg_sp [k], NULL);
2106 size = mono_type_stack_size (type, &align);
2108 ADD_TREE (t1, cli_addr);
2110 // fixme: align value type arguments to 8 byte boundary on the stack
2113 if (csig->hasthis) {
2115 args_size += sizeof (gpointer);
2117 this = mono_ctree_new_leaf (mp, MB_TERM_NOP);
2119 if (ISSTRUCT (csig->ret)) {
2120 size = mono_type_size (csig->ret, &align);
2121 vtype_num = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, VAL_UNKNOWN);
2127 t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2128 t2->data.p = ves_array_element_address;
2130 t1 = mono_ctree_new (mp, MB_TERM_CALL_I4, this, t2);
2131 t1->data.ci.args_size = args_size;
2132 t1->data.ci.vtype_num = vtype_num;
2134 t1 = mono_ctree_new (mp, mono_map_ldind_type (csig->ret, &svt), t1, NULL);
2137 mono_get_val_sizes (t1->svt, &size, &align);
2138 vnum = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, svt);
2140 t2 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2142 t1 = mono_ctree_new (mp, mono_map_store_svt_type (svt), t2, t1);
2145 ADD_TREE (t1, cli_addr);
2146 t1 = ctree_create_dup (mp, t1);
2147 PUSH_TREE (t1, t1->svt);
2149 } else if (array_set) {
2151 t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2152 t2->data.p = ves_array_element_address;
2154 t1 = mono_ctree_new (mp, MB_TERM_CALL_I4, this, t2);
2155 t1->data.ci.args_size = args_size;
2156 t1->data.ci.vtype_num = vtype_num;
2158 t1 = ctree_create_store (cfg, csig->params [nargs], t1, arg_sp [nargs], FALSE);
2159 ADD_TREE (t1, cli_addr);
2165 } else if (virtual || (csig->hasthis &&
2166 !(cm->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
2167 (cm->klass->marshalbyref || shared_to_unshared_call))) {
2169 mono_class_init (cm->klass);
2171 if (cm->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
2172 t2 = mono_ctree_new_leaf (mp, MB_TERM_INTF_ADDR);
2174 t2 = mono_ctree_new_leaf (mp, MB_TERM_VFUNC_ADDR);
2179 t2 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
2180 t2->data.p = arch_create_jit_trampoline (cm);
2183 t1 = mono_ctree_new (mp, mono_map_call_type (csig->ret, &svt), this, t2);
2184 t1->data.ci.args_size = args_size;
2185 t1->data.ci.vtype_num = vtype_num;
2188 if (csig->ret->type != MONO_TYPE_VOID) {
2191 ADD_TREE (t1, cli_addr);
2192 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2193 t1->data.i = vtype_num;
2194 PUSH_TREE (t1, VAL_POINTER);
2196 t1 = mono_store_tree (cfg, -1, t1, &t2);
2198 ADD_TREE (t1, cli_addr);
2199 PUSH_TREE (t2, t2->svt);
2202 ADD_TREE (t1, cli_addr);
2212 token = read32 (ip);
2215 c = mono_class_get (image, token);
2217 mono_class_init (c);
2219 t1 = mono_ctree_new (mp, MB_TERM_ISINST, *sp, NULL);
2222 PUSH_TREE (t1, VAL_POINTER);
2227 case CEE_CASTCLASS: {
2231 token = read32 (ip);
2234 c = mono_class_get (image, token);
2236 mono_class_init (c);
2238 t1 = mono_ctree_new (mp, MB_TERM_CASTCLASS, *sp, NULL);
2241 PUSH_TREE (t1, VAL_POINTER);
2246 case CEE_LDC_I4_S: {
2248 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2249 t1->data.i = *(const gint8 *)ip;
2251 PUSH_TREE (t1, VAL_I32);
2256 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2257 t1->data.i = read32 (ip);
2259 PUSH_TREE (t1, VAL_I32);
2271 case CEE_LDC_I4_8: {
2272 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2273 t1->data.i = (*ip) - CEE_LDC_I4_0;
2275 PUSH_TREE (t1, VAL_I32);
2279 //fixme: don't know if this is portable ?
2281 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2283 PUSH_TREE (t1, VAL_POINTER);
2288 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I8);
2289 t1->data.l = read64 (ip);
2291 PUSH_TREE (t1, VAL_I64);
2295 float *f = mono_alloc_static (sizeof (float));
2297 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_R4);
2301 PUSH_TREE (t1, VAL_DOUBLE);
2305 double *d = mono_alloc_static (sizeof (double));
2307 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_R8);
2311 PUSH_TREE (t1, VAL_DOUBLE);
2318 int n = (*ip) - CEE_LDLOC_0;
2321 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2322 t1->data.i = LOCAL_POS (n);
2323 if (!ISSTRUCT (LOCAL_TYPE (n)))
2324 t1 = ctree_create_load (cfg, LOCAL_TYPE (n), t1, &svt, FALSE);
2326 PUSH_TREE (t1, svt);
2332 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2333 t1->data.i = LOCAL_POS (*ip);
2334 if (!ISSTRUCT (LOCAL_TYPE (*ip)))
2335 t1 = ctree_create_load (cfg, LOCAL_TYPE (*ip), t1, &svt, FALSE);
2338 PUSH_TREE (t1, svt);
2341 case CEE_LDLOCA_S: {
2344 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2345 t1->data.i = LOCAL_POS (*ip);
2346 VARINFO (cfg, t1->data.i).isvolatile = 1;
2348 PUSH_TREE (t1, VAL_POINTER);
2355 int n = (*ip) - CEE_STLOC_0;
2359 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2360 t1->data.i = LOCAL_POS (n);
2362 if ((t2 = mono_stack_duplicate_used_var (cfg, stack, sp, t1->data.i)))
2363 ADD_TREE (t2, cli_addr);
2365 t1 = ctree_create_store (cfg, LOCAL_TYPE (n), t1, *sp, FALSE);
2366 ADD_TREE (t1, cli_addr);
2373 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2374 t1->data.i = LOCAL_POS (*ip);
2375 if ((t2 = mono_stack_duplicate_used_var (cfg, stack, sp, t1->data.i)))
2376 ADD_TREE (t2, cli_addr);
2378 t1 = ctree_create_store (cfg, LOCAL_TYPE (*ip), t1, *sp, FALSE);
2380 ADD_TREE (t1, cli_addr);
2387 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4)
2388 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i + sp [1]->data.i);
2390 t1 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], sp [1]);
2391 PUSH_TREE (t1, sp [0]->svt);
2398 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4)
2399 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i - sp [1]->data.i);
2401 t1 = mono_ctree_new (mp, MB_TERM_SUB, sp [0], sp [1]);
2402 PUSH_TREE (t1, sp [0]->svt);
2409 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4)
2410 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i & sp [1]->data.i);
2412 t1 = mono_ctree_new (mp, MB_TERM_AND, sp [0], sp [1]);
2413 PUSH_TREE (t1, sp [0]->svt);
2420 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4)
2421 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i | sp [1]->data.i);
2423 t1 = mono_ctree_new (mp, MB_TERM_OR, sp [0], sp [1]);
2424 PUSH_TREE (t1, sp [0]->svt);
2431 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4)
2432 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i ^ sp [1]->data.i);
2434 t1 = mono_ctree_new (mp, MB_TERM_XOR, sp [0], sp [1]);
2435 PUSH_TREE (t1, sp [0]->svt);
2442 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4) {
2443 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i * sp [1]->data.i);
2444 PUSH_TREE (t1, sp [0]->svt);
2446 MAKE_SPILLED_BI_ALU1 (MUL, sp [0], sp [1])
2454 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4) {
2455 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i / sp [1]->data.i);
2456 PUSH_TREE (t1, sp [0]->svt);
2458 MAKE_SPILLED_BI_ALU1 (DIV, sp [0], sp [1])
2466 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4) {
2467 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i % sp [1]->data.i);
2468 PUSH_TREE (t1, sp [0]->svt);
2470 MAKE_SPILLED_BI_ALU1 (REM, sp [0], sp [1])
2478 if (sp [0]->op == MB_TERM_CONST_I4 && sp [1]->op == MB_TERM_CONST_I4) {
2479 t1 = mono_ctree_new_icon4 (mp, sp [0]->data.i << sp [1]->data.i);
2480 PUSH_TREE (t1, sp [0]->svt);
2482 MAKE_SPILLED_BI_ALU1 (SHL, sp [0], sp [1])
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);
2492 PUSH_TREE (t1, sp [0]->svt);
2494 MAKE_SPILLED_BI_ALU1 (SHR, sp [0], sp [1])
2499 MAKE_BI_ALU (ADD_OVF)
2500 MAKE_BI_ALU (ADD_OVF_UN)
2501 MAKE_BI_ALU (SUB_OVF)
2502 MAKE_BI_ALU (SUB_OVF_UN)
2503 MAKE_SPILLED_BI_ALU (SHR_UN)
2504 MAKE_SPILLED_BI_ALU (MUL_OVF)
2505 MAKE_SPILLED_BI_ALU (MUL_OVF_UN)
2506 MAKE_SPILLED_BI_ALU (DIV_UN)
2507 MAKE_SPILLED_BI_ALU (REM_UN)
2509 MAKE_LDIND (LDIND_I1, MB_TERM_LDIND_I1, VAL_I32)
2510 MAKE_LDIND (LDIND_U1, MB_TERM_LDIND_U1, VAL_I32)
2511 MAKE_LDIND (LDIND_I2, MB_TERM_LDIND_I2, VAL_I32)
2512 MAKE_LDIND (LDIND_U2, MB_TERM_LDIND_U2, VAL_I32)
2513 MAKE_LDIND (LDIND_I, MB_TERM_LDIND_I4, VAL_I32)
2514 MAKE_LDIND (LDIND_I4, MB_TERM_LDIND_I4, VAL_I32)
2515 MAKE_LDIND (LDIND_REF, MB_TERM_LDIND_REF, VAL_POINTER)
2516 MAKE_LDIND (LDIND_U4, MB_TERM_LDIND_U4, VAL_I32)
2517 MAKE_LDIND (LDIND_I8, MB_TERM_LDIND_I8, VAL_I64)
2518 MAKE_LDIND (LDIND_R4, MB_TERM_LDIND_R4, VAL_DOUBLE)
2519 MAKE_LDIND (LDIND_R8, MB_TERM_LDIND_R8, VAL_DOUBLE)
2521 MAKE_STIND (STIND_I1, MB_TERM_STIND_I1)
2522 MAKE_STIND (STIND_I2, MB_TERM_STIND_I2)
2523 MAKE_STIND (STIND_I, MB_TERM_STIND_I4)
2524 MAKE_STIND (STIND_I4, MB_TERM_STIND_I4)
2525 MAKE_STIND (STIND_I8, MB_TERM_STIND_I8)
2526 MAKE_STIND (STIND_R4, MB_TERM_STIND_R4)
2527 MAKE_STIND (STIND_R8, MB_TERM_STIND_R8)
2528 MAKE_STIND (STIND_REF, MB_TERM_STIND_REF)
2530 MAKE_LDELEM (LDELEM_I1, MB_TERM_LDIND_I1, VAL_I32, 1)
2531 MAKE_LDELEM (LDELEM_U1, MB_TERM_LDIND_U1, VAL_I32, 1)
2532 MAKE_LDELEM (LDELEM_I2, MB_TERM_LDIND_I2, VAL_I32, 2)
2533 MAKE_LDELEM (LDELEM_U2, MB_TERM_LDIND_U2, VAL_I32, 2)
2534 MAKE_LDELEM (LDELEM_I, MB_TERM_LDIND_I4, VAL_I32, 4)
2535 MAKE_LDELEM (LDELEM_I4, MB_TERM_LDIND_I4, VAL_I32, 4)
2536 MAKE_LDELEM (LDELEM_REF, MB_TERM_LDIND_REF, VAL_POINTER, sizeof (gpointer))
2537 MAKE_LDELEM (LDELEM_U4, MB_TERM_LDIND_U4, VAL_I32, 4)
2538 MAKE_LDELEM (LDELEM_I8, MB_TERM_LDIND_I8, VAL_I64, 8)
2539 MAKE_LDELEM (LDELEM_R4, MB_TERM_LDIND_R4, VAL_DOUBLE, 4)
2540 MAKE_LDELEM (LDELEM_R8, MB_TERM_LDIND_R8, VAL_DOUBLE, 8)
2542 MAKE_STELEM (STELEM_I1, MB_TERM_STIND_I1, 1)
2543 MAKE_STELEM (STELEM_I2, MB_TERM_STIND_I2, 2)
2544 MAKE_STELEM (STELEM_I4, MB_TERM_STIND_I4, 4)
2545 MAKE_STELEM (STELEM_I, MB_TERM_STIND_I4, 4)
2546 MAKE_STELEM (STELEM_REF, MB_TERM_STIND_REF, sizeof (gpointer))
2547 MAKE_STELEM (STELEM_I8, MB_TERM_STIND_I8, 8)
2548 MAKE_STELEM (STELEM_R4, MB_TERM_STIND_R4, 4)
2549 MAKE_STELEM (STELEM_R8, MB_TERM_STIND_R8, 8)
2554 if (sp [0]->op == MB_TERM_CONST_I4)
2555 t1 = mono_ctree_new_icon4 (mp, -sp [0]->data.i);
2557 t1 = mono_ctree_new (mp, MB_TERM_NEG, sp [0], NULL);
2558 PUSH_TREE (t1, sp [0]->svt);
2564 if (sp [0]->op == MB_TERM_CONST_I4)
2565 t1 = mono_ctree_new_icon4 (mp, ~sp [0]->data.i);
2567 t1 = mono_ctree_new (mp, MB_TERM_NOT, sp [0], NULL);
2568 PUSH_TREE (t1, sp [0]->svt);
2574 int br_s = (*ip == CEE_BR_S);
2578 target = cli_addr + 2 + (signed char) *ip;
2580 target = cli_addr + 5 + (gint32) read32(ip);
2582 g_assert (target >= 0 && target <= header->code_size);
2583 g_assert (bcinfo [target].is_block_start);
2584 tbb = &cfg->bblocks [bcinfo [target].block_id];
2585 create_outstack (cfg, bb, stack, sp - stack);
2586 mark_reached (cfg, tbb, bb->outstack, bb->outdepth);
2588 t1 = mono_ctree_new_leaf (mp, MB_TERM_BR);
2590 ADD_TREE (t1, cli_addr);
2597 superblock_end = TRUE;
2604 token = read32 (ip);
2607 cm = mono_get_method (method->klass->image, token, NULL);
2610 t1 = mono_ctree_new_leaf (mp, MB_TERM_JMP);
2611 /* fixme: our magic trampoline code does not work in this case,
2612 * so I need to compile the method immediately */
2613 t1->data.p = mono_compile_method (cm);;
2615 ADD_TREE (t1, cli_addr);
2622 int leave_s = (*ip == CEE_LEAVE_S);
2626 target = cli_addr + 2 + (signed char) *ip;
2628 target = cli_addr + 5 + (gint32) read32(ip);
2630 g_assert (target >= 0 && target <= header->code_size);
2631 g_assert (bcinfo [target].is_block_start);
2632 tbb = &cfg->bblocks [bcinfo [target].block_id];
2634 /* empty the stack */
2635 while (sp != stack) {
2637 t1 = mono_ctree_new (mp, MB_TERM_POP, *sp, NULL);
2638 ADD_TREE (t1, cli_addr);
2641 mark_reached (cfg, tbb, NULL, 0);
2643 /* fixme: fault handler */
2645 if ((hb = mono_find_final_block (cfg, cli_addr, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
2646 mark_reached (cfg, hb, NULL, 0);
2647 t1 = mono_ctree_new_leaf (mp, MB_TERM_HANDLER);
2649 ADD_TREE (t1, cli_addr);
2652 t1 = mono_ctree_new_leaf (mp, MB_TERM_BR);
2654 ADD_TREE (t1, cli_addr);
2661 superblock_end = TRUE;
2678 case CEE_BRTRUE_S: {
2680 int near_jump = *ip == CEE_BRTRUE_S;
2684 t1 = mono_ctree_new (mp, MB_TERM_BRTRUE, sp [0], NULL);
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];
2694 create_outstack (cfg, bb, stack, sp - stack);
2695 mark_reached (cfg, tbb, bb->outstack, bb->outdepth);
2698 ip += near_jump ? 1: 4;
2699 ADD_TREE (t1, cli_addr);
2703 case CEE_BRFALSE_S: {
2705 int near_jump = *ip == CEE_BRFALSE_S;
2709 t1 = mono_ctree_new (mp, MB_TERM_BRFALSE, sp [0], NULL);
2712 target = cli_addr + 2 + (signed char) *ip;
2714 target = cli_addr + 5 + (gint32) read32 (ip);
2716 g_assert (target >= 0 && target <= header->code_size);
2717 g_assert (bcinfo [target].is_block_start);
2718 tbb = &cfg->bblocks [bcinfo [target].block_id];
2719 create_outstack (cfg, bb, stack, sp - stack);
2720 mark_reached (cfg, tbb, bb->outstack, bb->outdepth);
2723 ip += near_jump ? 1: 4;
2724 ADD_TREE (t1, cli_addr);
2728 MonoType *ret = signature->ret;
2732 if (ret->type != MONO_TYPE_VOID) {
2734 if (ISSTRUCT (ret)) {
2736 t1 = mono_ctree_new (mp, MB_TERM_RET_OBJ, *sp, NULL);
2737 t1->data.i = mono_class_value_size (ret->data.klass, &align);
2739 t1 = mono_ctree_new (mp, MB_TERM_RET, *sp, NULL);
2742 t1 = mono_ctree_new_leaf (mp, MB_TERM_RET_VOID);
2745 t1->last_instr = (ip == (header->code + header->code_size));
2747 ADD_TREE (t1, cli_addr);
2750 g_warning ("more values on stack at IL_%04x: %d", ip - header->code, sp - stack);
2751 mono_print_ctree (cfg, sp [-1]);
2754 superblock_end = TRUE;
2757 case CEE_ENDFINALLY: {
2760 t1 = mono_ctree_new_leaf (mp, MB_TERM_ENDFINALLY);
2761 ADD_TREE (t1, cli_addr);
2762 t1->last_instr = FALSE;
2764 g_assert (sp == stack);
2765 superblock_end = TRUE;
2772 int n = (*ip) - CEE_LDARG_0;
2779 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2780 t1->data.i = ARG_POS (n);
2781 if (!ISSTRUCT (ARG_TYPE (n)))
2782 t1 = ctree_create_load (cfg, ARG_TYPE (n), t1, &svt, TRUE);
2784 PUSH_TREE (t1, svt);
2793 *sp = arg_map [*ip];
2796 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2797 t1->data.i = ARG_POS (*ip);
2798 if (!ISSTRUCT (ARG_TYPE (*ip)))
2799 t1 = ctree_create_load (cfg, ARG_TYPE (*ip), t1, &svt, TRUE);
2800 PUSH_TREE (t1, svt);
2805 case CEE_LDARGA_S: {
2807 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2808 t1->data.i = ARG_POS (*ip);
2809 PUSH_TREE (t1, VAL_POINTER);
2817 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2818 t1->data.i = ARG_POS (*ip);
2819 t1 = ctree_create_store (cfg, ARG_TYPE (*ip), t1, *sp, TRUE);
2821 ADD_TREE (t1, cli_addr);
2829 /* fixme: maybe we should add more of these optimisations */
2830 if (sp [-1]->op == MB_TERM_CONST_I4) {
2832 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2833 t1->data.i = sp [-1]->data.i;
2834 PUSH_TREE (t1, VAL_I32);
2839 vnum = mono_allocate_intvar (cfg, sp - stack, sp [0]->svt);
2840 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2843 t2 = mono_ctree_new (mp, mono_map_store_svt_type (sp [0]->svt), t1, sp [0]);
2844 t2->svt = sp [0]->svt;
2845 ADD_TREE (t2, cli_addr);
2847 t1 = ctree_create_dup (mp, t2);
2848 PUSH_TREE (t1, t1->svt);
2849 t1 = ctree_create_dup (mp, t1);
2850 PUSH_TREE (t1, t1->svt);
2858 t1 = mono_ctree_new (mp, MB_TERM_POP, *sp, NULL);
2859 ADD_TREE (t1, cli_addr);
2863 case CEE_CKFINITE: {
2868 /* this instr. can throw exceptions as side effect,
2869 * so we cant eliminate dead code which contains CKFINITE opdodes.
2870 * Spilling to memory makes sure that we always perform
2872 vnum = mono_allocate_intvar (cfg, sp - stack, sp [0]->svt);
2873 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2876 t2 = mono_ctree_new (mp, MB_TERM_CKFINITE, *sp, NULL);
2878 t2 = mono_ctree_new (mp, mono_map_store_svt_type (sp [0]->svt), t1, t2);
2879 t2->svt = sp [0]->svt;
2880 ADD_TREE (t2, cli_addr);
2882 t1 = ctree_create_dup (mp, t2);
2883 PUSH_TREE (t1, t1->svt);
2889 if (sp [0]->op == MB_TERM_CONST_I4)
2890 t1 = mono_ctree_new_icon4 (mp, (guint8)sp [0]->data.i);
2892 t1 = mono_ctree_new (mp, MB_TERM_CONV_U1, *sp, NULL);
2893 PUSH_TREE (t1, VAL_I32);
2898 if (sp [0]->op == MB_TERM_CONST_I4)
2899 t1 = mono_ctree_new_icon4 (mp, (gint8)sp [0]->data.i);
2901 t1 = mono_ctree_new (mp, MB_TERM_CONV_I1, *sp, NULL);
2902 PUSH_TREE (t1, VAL_I32);
2907 if (sp [0]->op == MB_TERM_CONST_I4)
2908 t1 = mono_ctree_new_icon4 (mp, (guint16)sp [0]->data.i);
2910 t1 = mono_ctree_new (mp, MB_TERM_CONV_U2, *sp, NULL);
2911 PUSH_TREE (t1, VAL_I32);
2916 if (sp [0]->op == MB_TERM_CONST_I4)
2917 t1 = mono_ctree_new_icon4 (mp, (gint16)sp [0]->data.i);
2919 t1 = mono_ctree_new (mp, MB_TERM_CONV_I2, *sp, NULL);
2920 PUSH_TREE (t1, VAL_I32);
2926 if (sp [0]->op == MB_TERM_CONST_I4)
2929 t1 = mono_ctree_new (mp, MB_TERM_CONV_I4, *sp, NULL);
2930 PUSH_TREE (t1, VAL_I32);
2936 if (sp [0]->op == MB_TERM_CONST_I4)
2939 t1 = mono_ctree_new (mp, MB_TERM_CONV_U4, *sp, NULL);
2940 PUSH_TREE (t1, VAL_I32);
2945 t1 = mono_ctree_new (mp, MB_TERM_CONV_I8, *sp, NULL);
2946 PUSH_TREE (t1, VAL_I64);
2951 t1 = mono_ctree_new (mp, MB_TERM_CONV_U8, *sp, NULL);
2952 PUSH_TREE (t1, VAL_I64);
2957 t1 = mono_ctree_new (mp, MB_TERM_CONV_R8, *sp, NULL);
2958 PUSH_TREE (t1, VAL_DOUBLE);
2963 t1 = mono_ctree_new (mp, MB_TERM_CONV_R4, *sp, NULL);
2964 PUSH_TREE (t1, VAL_DOUBLE);
2969 t1 = mono_ctree_new (mp, MB_TERM_CONV_R_UN, *sp, NULL);
2970 PUSH_TREE (t1, VAL_DOUBLE);
2972 case CEE_CONV_OVF_I:
2973 case CEE_CONV_OVF_I4:
2976 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I4, *sp, NULL);
2977 PUSH_TREE (t1, VAL_I32);
2979 case CEE_CONV_OVF_I_UN:
2980 case CEE_CONV_OVF_I4_UN:
2983 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I4_UN, *sp, NULL);
2984 PUSH_TREE (t1, VAL_I32);
2986 case CEE_CONV_OVF_U:
2987 case CEE_CONV_OVF_U4:
2990 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U4, *sp, NULL);
2991 PUSH_TREE (t1, VAL_I32);
2993 case CEE_CONV_OVF_I1:
2996 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I1, *sp, NULL);
2997 PUSH_TREE (t1, VAL_I32);
2999 case CEE_CONV_OVF_I1_UN:
3002 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I1_UN, *sp, NULL);
3003 PUSH_TREE (t1, VAL_I32);
3005 case CEE_CONV_OVF_U1_UN:
3008 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U1_UN, *sp, NULL);
3009 PUSH_TREE (t1, VAL_I32);
3011 case CEE_CONV_OVF_U1:
3014 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U1, *sp, NULL);
3015 PUSH_TREE (t1, VAL_I32);
3017 case CEE_CONV_OVF_I2:
3020 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I2, *sp, NULL);
3021 PUSH_TREE (t1, VAL_I32);
3023 case CEE_CONV_OVF_U2_UN:
3026 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U2_UN, *sp, NULL);
3027 PUSH_TREE (t1, VAL_I32);
3029 case CEE_CONV_OVF_U2:
3032 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U2, *sp, NULL);
3033 PUSH_TREE (t1, VAL_I32);
3035 case CEE_CONV_OVF_I2_UN:
3038 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I2_UN, *sp, NULL);
3039 PUSH_TREE (t1, VAL_I32);
3041 case CEE_CONV_OVF_U8:
3044 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U8, *sp, NULL);
3045 PUSH_TREE (t1, VAL_I32);
3047 case CEE_CONV_OVF_U_UN:
3048 case CEE_CONV_OVF_U4_UN:
3049 // fixme: raise exceptions ?
3052 t1 = mono_ctree_new (mp, MB_TERM_CONV_I4, *sp, NULL);
3053 PUSH_TREE (t1, VAL_I32);
3055 case CEE_CONV_OVF_I8_UN:
3058 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I8_UN, *sp, NULL);
3059 PUSH_TREE (t1, VAL_I64);
3070 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3071 t1->data.i = LOCAL_POS (n);
3072 if (!ISSTRUCT (LOCAL_TYPE (n)))
3073 t1 = ctree_create_load (cfg, LOCAL_TYPE (n), t1, &svt, FALSE);
3076 PUSH_TREE (t1, svt);
3082 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3083 t1->data.i = LOCAL_POS (read16 (ip));
3084 VARINFO (cfg, t1->data.i).isvolatile = 1;
3086 PUSH_TREE (t1, VAL_POINTER);
3093 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3094 t1->data.i = LOCAL_POS (read16 (ip));
3095 if ((t2 = mono_stack_duplicate_used_var (cfg, stack, sp, t1->data.i)))
3096 ADD_TREE (t2, cli_addr);
3098 t1 = ctree_create_store (cfg, LOCAL_TYPE (read16 (ip)), t1, *sp, FALSE);
3100 ADD_TREE (t1, cli_addr);
3108 arg_pos = read16 (ip);
3111 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3112 t1->data.i = ARG_POS (arg_pos);
3113 t1 = ctree_create_store (cfg, ARG_TYPE (arg_pos), t1, *sp, TRUE);
3114 ADD_TREE (t1, cli_addr);
3126 t1 = mono_ctree_new_leaf (mp, MB_TERM_RETHROW);
3127 t1->data.i = mono_allocate_excvar (cfg);
3128 ADD_TREE (t1, cli_addr);
3135 token = read32 (ip);
3138 cm = mono_get_method (image, token, NULL);
3141 t1 = mono_ctree_new_leaf (mp, MB_TERM_LDFTN);
3143 PUSH_TREE (t1, VAL_POINTER);
3146 case CEE_LDVIRTFTN: {
3150 token = read32 (ip);
3154 cm = mono_get_method (image, token, NULL);
3157 if (cm->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
3158 t2 = mono_ctree_new_leaf (mp, MB_TERM_INTF_ADDR);
3160 t2 = mono_ctree_new_leaf (mp, MB_TERM_VFUNC_ADDR);
3164 t1 = mono_ctree_new (mp, MB_TERM_LDVIRTFTN, *sp, t2);
3166 PUSH_TREE (t1, VAL_POINTER);
3175 token = read32 (ip);
3176 class = mono_class_get (image, token);
3180 t1 = mono_ctree_new (mp, MB_TERM_INITOBJ, *sp, NULL);
3181 t1->data.i = mono_class_value_size (class, NULL);
3182 ADD_TREE (t1, cli_addr);
3192 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3193 t1->data.i = ARG_POS (n);
3194 if (!ISSTRUCT (ARG_TYPE (n)))
3195 t1 = ctree_create_load (cfg, ARG_TYPE (n), t1, &svt, TRUE);
3196 PUSH_TREE (t1, svt);
3205 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
3206 t1->data.i = ARG_POS (n);
3207 PUSH_TREE (t1, svt);
3214 token = read32 (ip);
3217 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
3218 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
3219 MonoType *type = mono_type_create_from_typespec (image, token);
3220 t1->data.i = mono_type_size (type, &align);
3221 mono_metadata_free_type (type);
3223 MonoClass *szclass = mono_class_get (image, token);
3224 mono_class_init (szclass);
3225 g_assert (szclass->valuetype);
3226 t1->data.i = mono_class_value_size (szclass, &align);
3229 PUSH_TREE (t1, VAL_I32);
3236 t1 = mono_ctree_new (mp, MB_TERM_CPSRC, sp [1], sp [2]);
3237 t1 = mono_ctree_new (mp, MB_TERM_CPBLK, sp [0], t1);
3238 ADD_TREE (t1, cli_addr);
3241 case CEE_UNALIGNED_: {
3243 // fixme: implement me
3246 case CEE_VOLATILE_: {
3248 // fixme: implement me
3251 case CEE_LOCALLOC: {
3255 t1 = mono_ctree_new (mp, MB_TERM_LOCALLOC, *sp, NULL);
3256 t1->data.i = header->init_locals;
3257 PUSH_TREE (t1, VAL_POINTER);
3264 t1 = mono_ctree_new (mp, MB_TERM_CPSRC, sp [1], sp [2]);
3265 t1 = mono_ctree_new (mp, MB_TERM_INITBLK, sp [0], t1);
3266 ADD_TREE (t1, cli_addr);
3270 g_error ("Unimplemented opcode at IL_%04x "
3271 "0xFE %02x", ip - header->code, *ip);
3276 g_warning ("unknown instruction `%s' at IL_%04X",
3277 mono_opcode_names [*ip], ip - header->code);
3278 if (mono_debug_format == MONO_DEBUG_FORMAT_NONE) {
3281 mono_print_forest (cfg, forest);
3282 g_assert_not_reached ();
3286 if ((depth = sp - stack)) {
3287 //printf ("DEPTH %d %d\n", depth, sp [0]->op);
3288 //mono_print_forest (cfg, forest);
3289 create_outstack (cfg, bb, stack, sp - stack);
3293 superblock_end = TRUE;
3296 superblock_end = TRUE;
3297 //printf ("unreached block %d\n", i);
3299 if (repeat_count >= 10) {
3300 /*mono_print_forest (cfg, forest);
3301 g_warning ("repeat count exceeded at ip: 0x%04x in %s\n", bb->cli_addr, cfg->method->name);*/
3305 //printf ("BBE %d %d %d %d\n", i, bb->reached, bb->finished, superblock_end);
3309 //printf ("REPEAT %d\n", repeat);
3310 mono_jit_stats.analyze_stack_repeat++;
3319 mono_cfg_free (MonoFlowGraph *cfg)
3323 for (i = 0; i < cfg->block_count; i++) {
3324 if (!cfg->bblocks [i].reached)
3326 g_ptr_array_free (cfg->bblocks [i].forest, TRUE);
3327 g_list_free (cfg->bblocks [i].succ);
3331 g_free (cfg->bcinfo);
3334 g_free (cfg->bblocks);
3336 g_array_free (cfg->varinfo, TRUE);
3338 mono_mempool_destroy (cfg->mp);
3341 static MonoFlowGraph *
3342 mono_cfg_new (MonoMethod *method)
3346 MonoMemPool *mp = mono_mempool_new ();
3348 g_assert (((MonoMethodNormal *)method)->header);
3350 cfg = mono_mempool_alloc0 (mp, sizeof (MonoFlowGraph));
3352 cfg->domain = mono_domain_get ();
3353 cfg->method = method;
3356 /* reserve space for caller saved registers */
3357 /* fixme: this is arch dependent */
3358 /* we save EAX, EDX, ECX - and ESP if we call finally handlers */
3359 cfg->locals_size = 16;
3361 /* fixme: we should also consider loader optimisation attributes */
3362 cfg->share_code = mono_jit_share_code;
3364 cfg->varinfo = g_array_new (FALSE, TRUE, sizeof (MonoVarInfo));
3366 SET_VARINFO (vi, 0, 0, 0, 0);
3367 g_array_append_val (cfg->varinfo, vi); /* add invalid value at position 0 */
3369 cfg->intvars = mono_mempool_alloc0 (mp, sizeof (guint16) * VAL_DOUBLE *
3370 ((MonoMethodNormal *)method)->header->max_stack);
3372 mono_analyze_flow (cfg);
3374 if (!mono_analyze_stack (cfg)) {
3375 mono_cfg_free (cfg);
3383 mono_get_runtime_method (MonoMethod* method)
3385 const char *name = method->name;
3386 guint8 *addr = NULL;
3387 gboolean delegate = FALSE;
3389 if (method->klass->parent == mono_defaults.multicastdelegate_class)
3392 if (delegate && *name == '.' && (strcmp (name, ".ctor") == 0)) {
3393 addr = (gpointer)mono_delegate_ctor;
3394 } else if (delegate && *name == 'I' && (strcmp (name, "Invoke") == 0)) {
3395 addr = arch_get_delegate_invoke (method);
3396 } else if (delegate && *name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
3397 addr = arch_get_delegate_begin_invoke (method);
3398 } else if (delegate && *name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
3399 /* this can raise exceptions, so we need a wrapper to save/restore LMF */
3400 method->addr = (gpointer)arch_end_invoke;
3401 addr = arch_create_native_wrapper (method);
3408 match_debug_method (MonoMethod* method)
3410 GList *tmp = mono_debug_methods;
3412 for (; tmp; tmp = tmp->next) {
3413 if (mono_method_desc_full_match (tmp->data, method))
3420 * mono_compile_method:
3421 * @method: pointer to the method info
3423 * JIT compilation of a single method.
3425 * Returns: a pointer to the newly created code.
3428 mono_compile_method (MonoMethod *method)
3430 MonoDomain *target_domain, *domain = mono_domain_get ();
3433 GHashTable *jit_code_hash;
3435 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
3436 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
3438 method->info = arch_create_native_wrapper (method);
3439 return method->info;
3442 if (mono_jit_share_code)
3443 target_domain = mono_root_domain;
3445 target_domain = domain;
3447 jit_code_hash = target_domain->jit_code_hash;
3449 if ((addr = g_hash_table_lookup (jit_code_hash, method))) {
3450 mono_jit_stats.methods_lookups++;
3454 mono_jit_stats.methods_compiled++;
3456 if (mono_jit_trace_calls || mono_jit_dump_asm || mono_jit_dump_forest) {
3457 printf ("Start JIT compilation of %s.%s:%s\n", method->klass->name_space,
3458 method->klass->name, method->name);
3461 if (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
3462 if (!(addr = mono_get_runtime_method (method))) {
3463 mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
3464 if (mono_debug_format != MONO_DEBUG_FORMAT_NONE)
3467 g_error ("Don't know how to exec runtime method %s.%s::%s",
3468 method->klass->name_space, method->klass->name, method->name);
3471 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
3473 gulong code_size_ratio;
3475 mono_profiler_method_jit (method);
3477 if (!(cfg = mono_cfg_new (method))) {
3478 mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
3482 cfg->code_size = MAX (header->code_size * 5, 256);
3483 cfg->start = cfg->code = g_malloc (cfg->code_size);
3485 /* fixme: make this arch independent */
3486 mono_debug_last_breakpoint_address = cfg->code;
3488 if (match_debug_method (method) || mono_debug_insert_breakpoint)
3489 x86_breakpoint (cfg->code);
3490 else if (mono_debug_format != MONO_DEBUG_FORMAT_NONE)
3491 x86_nop (cfg->code);
3493 if (mono_debug_insert_breakpoint > 0)
3494 mono_debug_insert_breakpoint--;
3496 if (!(ji = arch_jit_compile_cfg (target_domain, cfg))) {
3497 mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
3503 mono_jit_stats.allocated_code_size += cfg->code_size;
3505 code_size_ratio = cfg->code - cfg->start;
3506 if (code_size_ratio > mono_jit_stats.biggest_method_size) {
3507 mono_jit_stats.biggest_method_size = code_size_ratio;
3508 mono_jit_stats.biggest_method = method;
3510 code_size_ratio = (code_size_ratio * 100) / header->code_size;
3511 if (code_size_ratio > mono_jit_stats.max_code_size_ratio) {
3512 mono_jit_stats.max_code_size_ratio = code_size_ratio;
3513 mono_jit_stats.max_ratio_method = method;
3517 if (mono_jit_dump_asm) {
3518 char *id = g_strdup_printf ("%s.%s_%s", method->klass->name_space,
3519 method->klass->name, method->name);
3520 mono_disassemble_code (cfg->start, cfg->code - cfg->start, id);
3523 if (mono_debug_format != MONO_DEBUG_FORMAT_NONE)
3524 mono_debug_add_method (cfg);
3527 mono_jit_stats.native_code_size += ji->code_size;
3529 if (header->num_clauses) {
3530 int i, start_block, end_block;
3532 ji->num_clauses = header->num_clauses;
3533 ji->clauses = mono_mempool_alloc0 (target_domain->mp,
3534 sizeof (MonoJitExceptionInfo) * header->num_clauses);
3536 for (i = 0; i < header->num_clauses; i++) {
3537 MonoExceptionClause *ec = &header->clauses [i];
3538 MonoJitExceptionInfo *ei = &ji->clauses [i];
3540 ei->flags = ec->flags;
3541 ei->token_or_filter = ec->token_or_filter;
3543 g_assert (cfg->bcinfo [ec->try_offset].is_block_start);
3544 start_block = cfg->bcinfo [ec->try_offset].block_id;
3545 end_block = cfg->bcinfo [ec->try_offset + ec->try_len].block_id;
3546 g_assert (cfg->bcinfo [ec->try_offset + ec->try_len].is_block_start);
3548 ei->try_start = cfg->start + cfg->bblocks [start_block].addr;
3549 ei->try_end = cfg->start + cfg->bblocks [end_block].addr;
3551 g_assert (cfg->bcinfo [ec->handler_offset].is_block_start);
3552 start_block = cfg->bcinfo [ec->handler_offset].block_id;
3553 ei->handler_start = cfg->start + cfg->bblocks [start_block].addr;
3555 //printf ("TEST %x %x %x\n", ei->try_start, ei->try_end, ei->handler_start);
3559 mono_jit_info_table_add (target_domain, ji);
3561 mono_regset_free (cfg->rs);
3563 mono_cfg_free (cfg);
3565 mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
3568 if (mono_jit_trace_calls || mono_jit_dump_asm || mono_jit_dump_forest) {
3569 printf ("END JIT compilation of %s.%s:%s %p %p\n", method->klass->name_space,
3570 method->klass->name, method->name, method, addr);
3573 g_hash_table_insert (jit_code_hash, method, addr);
3578 /* this function is never called */
3580 ves_array_set (MonoArray *this, ...)
3582 g_assert_not_reached ();
3585 /* this function is never called */
3587 ves_array_get (MonoArray *this, ...)
3589 g_assert_not_reached ();
3594 * @assembly: reference to an assembly
3595 * @argc: argument count
3596 * @argv: argument vector
3598 * Start execution of a program.
3601 mono_jit_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
3603 MonoImage *image = assembly->image;
3604 MonoCLIImageInfo *iinfo;
3609 iinfo = image->image_info;
3610 method = mono_get_method (image, iinfo->cli_cli_header.ch_entry_point, NULL);
3612 rval = mono_runtime_run_main (method, argc, argv, &exc);
3617 #ifdef PLATFORM_WIN32
3618 #define GET_CONTEXT \
3619 struct sigcontext *ctx = (struct sigcontext*)_dummy;
3621 #define GET_CONTEXT \
3622 void **_p = (void **)&_dummy; \
3623 struct sigcontext *ctx = (struct sigcontext *)++_p;
3627 sigfpe_signal_handler (int _dummy)
3632 exc = mono_get_exception_divide_by_zero ();
3634 arch_handle_exception (ctx, exc);
3636 g_error ("we should never reach this code");
3640 sigill_signal_handler (int _dummy)
3645 exc = mono_get_exception_execution_engine ("SIGILL");
3647 arch_handle_exception (ctx, exc);
3649 g_error ("we should never reach this code");
3653 sigsegv_signal_handler (int _dummy)
3658 exc = mono_get_exception_null_reference ();
3660 arch_handle_exception (ctx, exc);
3662 g_error ("we should never reach this code");
3666 * mono_thread_abort:
3667 * @obj: exception object
3669 * abort the thread, print exception information and stack trace
3672 mono_thread_abort (MonoObject *obj)
3674 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
3679 longjmp (*jit_tls->env, (int)obj);
3688 mono_thread_start_cb (gpointer stack_start)
3690 MonoJitTlsData *jit_tls;
3692 jit_tls = g_new0 (MonoJitTlsData, 1);
3694 TlsSetValue (mono_jit_tls_id, jit_tls);
3696 jit_tls->abort_func = mono_thread_abort;
3697 jit_tls->end_of_stack = stack_start;
3700 static CRITICAL_SECTION ms;
3703 mono_runtime_install_handlers (void)
3705 #ifndef PLATFORM_WIN32
3706 struct sigaction sa;
3709 #ifdef PLATFORM_WIN32
3711 win32_seh_set_handler(SIGFPE, sigfpe_signal_handler);
3712 win32_seh_set_handler(SIGILL, sigill_signal_handler);
3713 win32_seh_set_handler(SIGSEGV, sigsegv_signal_handler);
3714 #else /* !PLATFORM_WIN32 */
3716 sa.sa_handler = sigfpe_signal_handler;
3717 sigemptyset (&sa.sa_mask);
3719 g_assert (syscall (SYS_sigaction, SIGFPE, &sa, NULL) != -1);
3722 sa.sa_handler = sigill_signal_handler;
3723 sigemptyset (&sa.sa_mask);
3725 g_assert (syscall (SYS_sigaction, SIGILL, &sa, NULL) != -1);
3729 sa.sa_handler = sigsegv_signal_handler;
3730 sigemptyset (&sa.sa_mask);
3732 g_assert (syscall (SYS_sigaction, SIGSEGV, &sa, NULL) != -1);
3734 #endif /* PLATFORM_WIN32 */
3738 mono_jit_init (char *file) {
3743 mono_runtime_install_handlers ();
3746 mono_add_internal_call ("System.Array::Set", ves_array_set);
3747 mono_add_internal_call ("System.Array::Get", ves_array_get);
3748 mono_add_internal_call ("System.Array::Address", ves_array_element_address);
3749 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
3750 ves_icall_get_frame_info);
3752 metadata_section = &ms;
3753 InitializeCriticalSection (metadata_section);
3755 mono_jit_tls_id = TlsAlloc ();
3756 mono_thread_start_cb (&file);
3758 mono_install_trampoline (arch_create_jit_trampoline);
3759 mono_install_remoting_trampoline (arch_create_remoting_trampoline);
3760 mono_install_handler (arch_get_throw_exception ());
3761 mono_install_runtime_invoke (arch_runtime_invoke);
3763 domain = mono_init (file);
3764 mono_runtime_init (domain, mono_thread_start_cb);
3770 mono_jit_cleanup (MonoDomain *domain)
3772 mono_debug_cleanup ();
3774 #ifdef PLATFORM_WIN32
3775 win32_seh_cleanup();
3778 mono_runtime_cleanup (domain);
3780 mono_domain_unload (domain, TRUE);
3782 if (mono_jit_stats.enabled) {
3783 g_print ("Mono Jit statistics\n");
3784 g_print ("Compiled methods: %ld\n", mono_jit_stats.methods_compiled);
3785 g_print ("Methods cache lookup: %ld\n", mono_jit_stats.methods_lookups);
3786 g_print ("Method trampolines: %ld\n", mono_jit_stats.method_trampolines);
3787 g_print ("Basic blocks: %ld\n", mono_jit_stats.basic_blocks);
3788 g_print ("Max basic blocks: %ld\n", mono_jit_stats.max_basic_blocks);
3789 g_print ("Allocated vars: %ld\n", mono_jit_stats.allocate_var);
3790 g_print ("Analyze stack repeat: %ld\n", mono_jit_stats.analyze_stack_repeat);
3791 g_print ("Compiled CIL code size: %ld\n", mono_jit_stats.cil_code_size);
3792 g_print ("Native code size: %ld\n", mono_jit_stats.native_code_size);
3793 g_print ("Max code size ratio: %.2f (%s::%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
3794 mono_jit_stats.max_ratio_method->klass->name, mono_jit_stats.max_ratio_method->name);
3795 g_print ("Biggest method: %ld (%s::%s)\n", mono_jit_stats.biggest_method_size,
3796 mono_jit_stats.biggest_method->klass->name, mono_jit_stats.biggest_method->name);
3797 g_print ("Code reallocs: %ld\n", mono_jit_stats.code_reallocs);
3798 g_print ("Allocated code size: %ld\n", mono_jit_stats.allocated_code_size);
3799 g_print ("Inlineable methods: %ld\n", mono_jit_stats.inlineable_methods);
3800 g_print ("Inlined methods: %ld\n", mono_jit_stats.inlined_methods);
3802 g_print ("\nCreated object count: %ld\n", mono_stats.new_object_count);
3803 g_print ("Initialized classes: %ld\n", mono_stats.initialized_class_count);
3804 g_print ("Used classes: %ld\n", mono_stats.used_class_count);
3805 g_print ("Static data size: %ld\n", mono_stats.class_static_data_size);
3806 g_print ("VTable data size: %ld\n", mono_stats.class_vtable_size);
3809 DeleteCriticalSection (metadata_section);