2 * testjit.c: The mono JIT compiler.
5 * Dietmar Maurer (dietmar@ximian.com)
7 * (C) 2001 Ximian, Inc.
16 #include <mono/metadata/assembly.h>
17 #include <mono/metadata/loader.h>
18 #include <mono/metadata/cil-coff.h>
19 #include <mono/metadata/tabledefs.h>
20 #include <mono/metadata/class.h>
21 #include <mono/metadata/object.h>
22 #include <mono/metadata/mono-endian.h>
23 #include <mono/metadata/tokentype.h>
24 #include <mono/arch/x86/x86-codegen.h>
31 * Pull the list of opcodes
33 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
37 #include "mono/cil/opcode.def"
42 #define OPDEF(a,b,c,d,e,f,g,h,i,j) b,
43 static char *opcode_names [] = {
44 #include "mono/cil/opcode.def"
48 #define SET_VARINFO(vi,t,k,o,s) do { vi.type=t; vi.kind=k; vi.offset=o; vi.size=s; } while (0)
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_##name, sp [0], sp [1]); \
59 target = cli_addr + 2 + (signed char) *ip; \
61 target = cli_addr + 5 + (gint32) read32 (ip); \
62 g_assert (target >= 0 && target <= header->code_size); \
63 g_assert (bcinfo [target].is_block_start); \
64 tbb = &cfg->bblocks [bcinfo [target].block_id]; \
65 create_outstack (cfg, bb, stack, sp - stack); \
66 mark_reached (cfg, tbb, bb->outstack, bb->outdepth); \
69 ip += near_jump ? 1: 4; \
73 #define MAKE_BI_ALU(name) \
77 t1 = mono_ctree_new (mp, MB_TERM_##name, sp [0], sp [1]); \
78 g_assert (sp [0]->svt == sp [1]->svt); \
79 PUSH_TREE (t1, sp [0]->svt); \
83 #define MAKE_LDIND(name, op, svt) \
87 t1 = mono_ctree_new (mp, op, *sp, NULL); \
88 PUSH_TREE (t1, svt); \
92 #define MAKE_LDELEM(name, op, svt, s) \
96 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4); \
98 t1 = mono_ctree_new (mp, MB_TERM_MUL, sp [1], t1); \
99 t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4); \
100 t2->data.i = G_STRUCT_OFFSET (MonoArray, vector); \
101 t2 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], t2); \
102 t1 = mono_ctree_new (mp, MB_TERM_ADD, t1, t2); \
103 t1 = mono_ctree_new (mp, op, t1, NULL); \
104 PUSH_TREE (t1, svt); \
108 #define MAKE_STIND(name, op) \
112 t1 = mono_ctree_new (mp, op, sp [0], sp [1]); \
117 #define MAKE_STELEM(name, op, s) \
121 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4); \
123 t1 = mono_ctree_new (mp, MB_TERM_MUL, sp [1], t1); \
124 t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4); \
125 t2->data.i = G_STRUCT_OFFSET (MonoArray, vector); \
126 t2 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], t2); \
127 t1 = mono_ctree_new (mp, MB_TERM_ADD, t1, t2); \
128 t1 = mono_ctree_new (mp, op, t1, sp [2]); \
133 /* Whether to dump the assembly code after genreating it */
134 gboolean mono_jit_dump_asm = FALSE;
136 /* Whether to dump the forest */
137 gboolean mono_jit_dump_forest = FALSE;
139 /* Whether to print function call traces */
140 gboolean mono_jit_trace_calls = FALSE;
143 * We sometimes need static data, for example the forest generator need it to
144 * store constants or class data.
146 inline static gpointer
147 mono_alloc_static (int size)
149 return g_malloc (size);
151 inline static gpointer
152 mono_alloc_static0 (int size)
154 return g_malloc0 (size);
158 typedef void (*MonoCCtor) (void);
161 * mono_jit_init_class:
162 * @klass: the class to initialise
164 * Initialise the class @klass by calling the class
168 mono_jit_init_class (MonoClass *klass)
174 if (!klass->metadata_inited)
175 mono_class_metadata_init (klass);
180 if (klass->parent && !klass->parent->inited)
181 mono_jit_init_class (klass->parent);
185 for (i = 0; i < klass->method.count; ++i) {
186 method = klass->methods [i];
187 if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
188 (strcmp (".cctor", method->name) == 0)) {
190 cctor = arch_compile_method (method);
195 /* No class constructor found */
199 map_store_svt_type (int svt)
204 return MB_TERM_STIND_I4;
206 return MB_TERM_STIND_I8;
208 return MB_TERM_STIND_R8;
210 g_assert_not_reached ();
217 map_stvalue_type (MonoClass *class)
221 g_assert (class->valuetype);
224 mono_jit_init_class (class);
226 size = class->instance_size - sizeof (MonoObject);
230 return MB_TERM_STIND_I4;
232 return MB_TERM_STIND_I2;
234 return MB_TERM_STIND_I1;
236 return MB_TERM_STIND_OBJ;
241 * @type: the type to map
243 * Translates the MonoType @type into the corresponding store opcode
244 * for the code generator.
247 map_stind_type (MonoType *type)
250 return MB_TERM_STIND_I4;
252 switch (type->type) {
255 case MONO_TYPE_BOOLEAN:
256 return MB_TERM_STIND_I1;
260 return MB_TERM_STIND_I2;
264 case MONO_TYPE_CLASS:
265 case MONO_TYPE_OBJECT:
266 case MONO_TYPE_STRING:
268 case MONO_TYPE_SZARRAY:
269 case MONO_TYPE_ARRAY:
270 return MB_TERM_STIND_I4;
273 return MB_TERM_STIND_I8;
275 return MB_TERM_STIND_R4;
277 return MB_TERM_STIND_R8;
278 case MONO_TYPE_VALUETYPE:
279 return map_stvalue_type (type->data.klass);
281 g_warning ("unknown type %02x", type->type);
282 g_assert_not_reached ();
285 g_assert_not_reached ();
291 * @type: the type to map
293 * Translates the MonoType @type into the corresponding load opcode
294 * for the code generator.
297 map_ldind_type (MonoType *type, MonoValueType *svt)
301 return MB_TERM_LDIND_I4;
304 switch (type->type) {
307 return MB_TERM_LDIND_I1;
309 case MONO_TYPE_BOOLEAN:
311 return MB_TERM_LDIND_U1;
314 return MB_TERM_LDIND_I2;
318 return MB_TERM_LDIND_U2;
322 return MB_TERM_LDIND_I4;
325 return MB_TERM_LDIND_U4;
326 case MONO_TYPE_CLASS:
327 case MONO_TYPE_OBJECT:
328 case MONO_TYPE_STRING:
330 case MONO_TYPE_SZARRAY:
331 case MONO_TYPE_ARRAY:
333 return MB_TERM_LDIND_U4;
337 return MB_TERM_LDIND_I8;
340 return MB_TERM_LDIND_R4;
343 return MB_TERM_LDIND_R8;
344 case MONO_TYPE_VALUETYPE: {
346 size = mono_type_size (type, &align);
351 return MB_TERM_LDIND_U4;
354 return MB_TERM_LDIND_U2;
357 return MB_TERM_LDIND_U1;
359 g_assert_not_reached ();
363 g_warning ("unknown type %02x", type->type);
364 g_assert_not_reached ();
367 g_assert_not_reached ();
373 * @type: the type to map
375 * Translates the MonoType @type into the corresponding call opcode
376 * for the code generator.
379 map_call_type (MonoType *type, MonoValueType *svt)
381 switch (type->type) {
384 return MB_TERM_CALL_VOID;
387 case MONO_TYPE_BOOLEAN:
395 return MB_TERM_CALL_I4;
396 case MONO_TYPE_VALUETYPE:
398 return MB_TERM_CALL_VOID;
399 case MONO_TYPE_CLASS:
400 case MONO_TYPE_OBJECT:
401 case MONO_TYPE_STRING:
403 case MONO_TYPE_SZARRAY:
405 return MB_TERM_CALL_I4;
409 return MB_TERM_CALL_I8;
413 return MB_TERM_CALL_R8;
415 g_warning ("unknown type %02x", type->type);
416 g_assert_not_reached ();
419 g_assert_not_reached ();
424 * prints the tree to stdout
427 mono_print_ctree (MBTree *tree)
434 arity = (tree->left != NULL) + (tree->right != NULL);
437 printf (" (%s", mono_burg_term_string [tree->op]);
439 printf (" %s", mono_burg_term_string [tree->op]);
443 printf ("[%d]", tree->data.i);
447 g_assert (!(tree->right && !tree->left));
449 mono_print_ctree (tree->left);
450 mono_print_ctree (tree->right);
457 * prints the whole forest to stdout
460 mono_print_forest (GPtrArray *forest)
462 const int top = forest->len;
465 for (i = 0; i < top; i++) {
466 MBTree *t = (MBTree *) g_ptr_array_index (forest, i);
468 mono_print_ctree (t);
475 * mono_disassemble_code:
476 * @code: a pointer to the code
477 * @size: the code size in bytes
479 * Disassemble to code to stdout.
482 mono_disassemble_code (guint8 *code, int size)
487 if (!(ofd = fopen ("/tmp/test.s", "w")))
488 g_assert_not_reached ();
490 for (i = 0; i < size; ++i)
491 fprintf (ofd, ".byte %d\n", (unsigned int) code [i]);
495 system ("as /tmp/test.s -o /tmp/test.o;objdump -d /tmp/test.o");
499 arch_allocate_var (MonoFlowGraph *cfg, int size, int align, MonoValueKind kind, MonoValueType type)
505 case MONO_LOCALVAR: {
506 cfg->locals_size += align - 1;
507 cfg->locals_size &= ~(align - 1);
508 cfg->locals_size += size;
510 SET_VARINFO (vi, type, kind, - cfg->locals_size, size);
511 g_array_append_val (cfg->varinfo, vi);
515 SET_VARINFO (vi, type, kind, cfg->args_size + 8, size);
516 g_array_append_val (cfg->varinfo, vi);
518 cfg->args_size += align - 1;
519 cfg->args_size &= ~(align - 1);
520 cfg->args_size += size;
524 g_assert_not_reached ();
527 return cfg->varinfo->len - 1;
531 mono_get_val_sizes (MonoValueType type, int *size, int *align)
535 *size = *align = sizeof (gint32);
538 *size = *align = sizeof (gint64);
541 *size = *align = sizeof (gpointer);
544 *size = *align = sizeof (double);
547 g_assert_not_reached ();
552 mono_allocate_intvar (MonoFlowGraph *cfg, int slot, MonoValueType type)
554 int size, align, vnum;
556 g_assert (type != VAL_UNKNOWN);
558 if ((vnum = cfg->intvars [type - 1 + slot * VAL_DOUBLE]))
561 mono_get_val_sizes (type, &size, &align);
563 return cfg->intvars[type - 1 + slot * VAL_DOUBLE] = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, type);
568 * @cfg: pointer to the control flow graph
569 * @type: the type of the value to load
570 * @addr: the address of the value
572 * Creates a tree to load the value at address @addr.
574 inline static MBTree *
575 ctree_create_load (MonoFlowGraph *cfg, MonoType *type, MBTree *addr, MonoValueType *svt)
577 MonoMemPool *mp = cfg->mp;
578 int ldind, size, align, vnum;
581 if (type->type == MONO_TYPE_VALUETYPE) {
582 size = mono_type_size (type, &align);
584 if (size > 4 || size == 3) {
586 vnum = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, VAL_UNKNOWN);
587 t = mono_ctree_new (mp, MB_TERM_LDIND_OBJ, addr, NULL);
593 ldind = map_ldind_type (type, svt);
594 t = mono_ctree_new (mp, ldind, addr, NULL);
600 * ctree_create_store:
601 * @mp: pointer to a memory pool
602 * @addr_type: address type (MB_TERM_ADDR_L or MB_TERM_ADDR_G)
603 * @s: the value (tree) to store
604 * @type: the type of the value
605 * @addr: the address of the value
607 * Creates a tree to store the value @s at address @addr.
609 inline static MBTree *
610 ctree_create_store (MonoMemPool *mp, int addr_type, MBTree *s, MonoType *type, gpointer addr)
612 int stind = map_stind_type (type);
615 t = mono_ctree_new_leaf (mp, addr_type);
617 t = mono_ctree_new (mp, stind, t, s);
622 inline static MBTree *
623 ctree_dup_address (MonoMemPool *mp, MBTree *s)
631 t = mono_ctree_new_leaf (mp, s->op);
632 t->data.i = s->data.i;
633 t->svt = VAL_POINTER;
636 g_warning ("unknown tree opcode %d", s->op);
637 g_assert_not_reached ();
644 * Create a duplicate of the value of a tree. This is
645 * easy for trees starting with LDIND/STIND, since the
646 * duplicate is simple a LDIND tree with the same address.
647 * For other trees we have to split the tree into one tree
648 * storing the value to a new temporary variable, and
649 * another tree which loads that value back. We can then
650 * duplicate the second tree.
653 ctree_create_dup (MonoMemPool *mp, MBTree *s)
658 case MB_TERM_STIND_I1:
659 case MB_TERM_LDIND_I1:
660 t = ctree_dup_address (mp, s->left);
661 t = mono_ctree_new (mp, MB_TERM_LDIND_I1, t, NULL);
664 case MB_TERM_STIND_I2:
665 case MB_TERM_LDIND_I2:
666 t = ctree_dup_address (mp, s->left);
667 t = mono_ctree_new (mp, MB_TERM_LDIND_I2, t, NULL);
670 case MB_TERM_STIND_I4:
671 case MB_TERM_LDIND_I4:
672 t = ctree_dup_address (mp, s->left);
673 t = mono_ctree_new (mp, MB_TERM_LDIND_I4, t, NULL);
676 case MB_TERM_LDIND_U4:
677 t = ctree_dup_address (mp, s->left);
678 t = mono_ctree_new (mp, MB_TERM_LDIND_U4, t, NULL);
681 case MB_TERM_STIND_I8:
682 case MB_TERM_LDIND_I8:
683 t = ctree_dup_address (mp, s->left);
684 t = mono_ctree_new (mp, MB_TERM_LDIND_I8, t, NULL);
687 case MB_TERM_STIND_R4:
688 case MB_TERM_LDIND_R4:
689 t = ctree_dup_address (mp, s->left);
690 t = mono_ctree_new (mp, MB_TERM_LDIND_R4, t, NULL);
693 case MB_TERM_STIND_R8:
694 case MB_TERM_LDIND_R8:
695 t = ctree_dup_address (mp, s->left);
696 t = mono_ctree_new (mp, MB_TERM_LDIND_R8, t, NULL);
700 g_warning ("unknown op \"%s\"", mono_burg_term_string [s->op]);
701 g_assert_not_reached ();
708 mono_store_tree (MonoFlowGraph *cfg, int slot, MBTree *s, MBTree **dup)
710 MonoMemPool *mp = cfg->mp;
715 case MB_TERM_STIND_I1:
716 case MB_TERM_LDIND_I1:
717 case MB_TERM_STIND_I2:
718 case MB_TERM_LDIND_I2:
719 case MB_TERM_STIND_I4:
720 case MB_TERM_LDIND_I4:
721 case MB_TERM_STIND_I8:
722 case MB_TERM_LDIND_I8:
723 case MB_TERM_STIND_R4:
724 case MB_TERM_LDIND_R4:
725 case MB_TERM_STIND_R8:
726 case MB_TERM_LDIND_R8: {
728 vnum = mono_allocate_intvar (cfg, slot, s->svt);
730 if (s->left->op == MB_TERM_ADDR_L && s->left->data.i == vnum) {
732 *dup = ctree_create_dup (mp, s);
738 *dup = ctree_create_dup (mp, s);
743 g_assert (s->svt != VAL_UNKNOWN);
746 vnum = mono_allocate_intvar (cfg, slot, s->svt);
749 mono_get_val_sizes (s->svt, &size, &align);
750 vnum = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, s->svt);
753 t = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
756 t = mono_ctree_new (mp, map_store_svt_type (s->svt), t, s);
762 mono_store_tree (cfg, -1, t, dup);
768 mono_cfg_new (MonoMethod *method, MonoMemPool *mp)
773 cfg = mono_mempool_alloc0 (mp, sizeof (MonoFlowGraph));
775 cfg->method = method;
778 cfg->varinfo = g_array_new (FALSE, TRUE, sizeof (MonoVarInfo));
780 SET_VARINFO (vi, 0, 0, 0, 0);
781 g_array_append_val (cfg->varinfo, vi); /* add invalid value at position 0 */
783 cfg->intvars = mono_mempool_alloc0 (mp, sizeof (guint16) * VAL_DOUBLE *
784 ((MonoMethodNormal *)method)->header->max_stack);
789 mono_cfg_free (MonoFlowGraph *cfg)
793 for (i = 0; i < cfg->block_count; i++) {
794 g_ptr_array_free (cfg->bblocks [i].forest, TRUE);
797 g_array_free (cfg->varinfo, TRUE);
800 #define CREATE_BLOCK(t) {if (!bcinfo [t].is_block_start) {block_count++;bcinfo [t].is_block_start = 1; }}
803 mono_analyze_flow (MonoFlowGraph *cfg)
805 MonoMethod *method = cfg->method;
806 MonoMemPool *mp = cfg->mp;
807 register const unsigned char *ip, *end;
808 MonoMethodHeader *header;
809 MonoBytecodeInfo *bcinfo;
810 MonoBBlock *bblocks, *bb;
814 header = ((MonoMethodNormal *)method)->header;
816 bcinfo = mono_mempool_alloc0 (mp, header->code_size * sizeof (MonoBytecodeInfo));
817 bcinfo [0].is_block_start = 1;
822 end = ip + header->code_size;
824 /* fixme: add block boundaries for exceptions */
827 guint32 cli_addr = ip - header->code;
829 //printf ("IL%04x OPCODE %s\n", cli_addr, opcode_names [*ip]);
832 CREATE_BLOCK (cli_addr);
923 case CEE_CONV_OVF_I_UN:
924 case CEE_CONV_OVF_U_UN:
925 case CEE_CONV_OVF_I1_UN:
926 case CEE_CONV_OVF_U1_UN:
927 case CEE_CONV_OVF_I2_UN:
928 case CEE_CONV_OVF_U2_UN:
929 case CEE_CONV_OVF_I4_UN:
930 case CEE_CONV_OVF_U4_UN:
931 case CEE_CONV_OVF_I8_UN:
932 case CEE_CONV_OVF_U8_UN:
935 case CEE_CONV_OVF_I1:
936 case CEE_CONV_OVF_U1:
937 case CEE_CONV_OVF_I2:
938 case CEE_CONV_OVF_U2:
939 case CEE_CONV_OVF_I4:
940 case CEE_CONV_OVF_U4:
941 case CEE_CONV_OVF_I8:
942 case CEE_CONV_OVF_U8:
1000 offset = read32 (ip);
1002 CREATE_BLOCK (cli_addr + 5 + offset);
1032 case CEE_BLE_UN_S: {
1035 offset = (signed char)*ip;
1037 CREATE_BLOCK (cli_addr + 2 + offset);
1042 gint32 i, st, target, n;
1046 st = cli_addr + 5 + 4 * n;
1049 for (i = 0; i < n; i++) {
1050 target = read32 (ip) + st;
1052 CREATE_BLOCK (target);
1069 g_error ("Unimplemented opcode at IL_%04x "
1070 "0xFE %02x", ip - header->code, *ip);
1076 g_warning ("unknown instruction `%s' at IL_%04X",
1077 opcode_names [*ip], ip - header->code);
1078 g_assert_not_reached ();
1083 g_assert (block_count);
1085 bb = bblocks = mono_mempool_alloc0 (mp, sizeof (MonoBBlock) * block_count);
1088 bblocks [0].reached = 1;
1090 for (i = 0; i < header->code_size; i++) {
1091 if (bcinfo [i].is_block_start) {
1094 bb [-1].length = i - bb [-1].cli_addr;
1095 bcinfo [i].block_id = block_count;
1100 bb [-1].length = header->code_size - bb [-1].cli_addr;
1102 cfg->bcinfo = bcinfo;
1103 cfg->bblocks = bblocks;
1104 cfg->block_count = block_count;
1108 * ves_array_element_address:
1109 * @this: a pointer to the array object
1111 * Returns: the address of an array element.
1114 ves_array_element_address (MonoArray *this, ...)
1121 g_assert (this != NULL);
1125 class = this->obj.klass;
1127 ind = va_arg(ap, int) - this->bounds [0].lower_bound;
1128 for (i = 1; i < class->rank; i++) {
1129 ind = ind*this->bounds [i].length + va_arg(ap, int) -
1130 this->bounds [i].lower_bound;;
1133 esize = mono_array_element_size (class);
1134 ea = (gpointer*)((char*)this->vector + (ind * esize));
1135 //printf ("AADDRESS %p %p %d\n", this, ea, ind);
1143 mono_array_new_va (MonoMethod *cm, ...)
1147 guint32 *lower_bounds;
1148 int pcount = cm->signature->param_count;
1149 int rank = cm->klass->rank;
1154 lengths = alloca (sizeof (guint32) * pcount);
1155 for (i = 0; i < pcount; ++i)
1156 lengths [i] = d = va_arg(ap, int);
1158 if (rank == pcount) {
1159 /* Only lengths provided. */
1160 lower_bounds = NULL;
1162 g_assert (pcount == (rank * 2));
1163 /* lower bounds are first. */
1164 lower_bounds = lengths;
1169 return mono_array_new_full (cm->klass, lengths, lower_bounds);
1172 #define ADD_TREE(t) do { g_ptr_array_add (forest, (t)); } while (0)
1173 #define PUSH_TREE(t,k) do { *sp = t; sp++; t->svt = k; } while (0)
1175 #define LOCAL_POS(n) (1 + n)
1176 #define LOCAL_TYPE(n) ((header)->locals [(n)])
1178 #define ARG_POS(n) (firstarg + n)
1179 #define ARG_TYPE(n) ((n) ? (signature)->params [(n) - (signature)->hasthis] : \
1180 (signature)->hasthis ? &method->klass->this_arg: (signature)->params [(0)])
1183 create_outstack (MonoFlowGraph *cfg, MonoBBlock *bb, MBTree **stack, int depth)
1185 MonoMemPool *mp = cfg->mp;
1186 MBTree **c = stack, *t1, *t2;
1187 GPtrArray *forest = bb->forest;
1190 g_assert (bb->reached);
1196 g_assert (bb->outdepth == depth);
1200 bb->outdepth = depth;
1201 bb->outstack = mono_mempool_alloc (mp, depth * sizeof (MBTree *));
1203 for (i = 0; i < depth; i++) {
1204 if ((t1 = mono_store_tree (cfg, i, c [i], &t2)))
1206 bb->outstack [i] = t2;
1211 mark_reached (MonoFlowGraph *cfg, MonoBBlock *target, MBTree **stack, int depth)
1213 MonoMemPool *mp = cfg->mp;
1216 if (target->reached)
1219 target->reached = 1;
1226 if (target->instack) {
1227 g_assert (target->indepth == depth);
1231 target->indepth = depth;
1232 target->instack = mono_mempool_alloc (mp, depth * sizeof (MBTree *));
1234 for (i = 0; i < depth; i++) {
1235 target->instack [i] = ctree_create_dup (mp, stack [i]);
1241 #define MARK_REACHED(bb) do { if (!bb->reached) { bb->reached = 1; }} while (0)
1245 * @method: the method to analyse
1246 * @mp: a memory pool
1247 * @locals_size: to return the size of local vars
1249 * This is the architecture independent part of JIT compilation.
1250 * It creates a forest of trees which can then be fed into the
1251 * architecture dependent code generation.
1253 * The algorithm is from Andi Krall, the same is used in CACAO
1256 mono_analyze_stack (MonoFlowGraph *cfg)
1258 MonoMethod *method = cfg->method;
1259 MonoMemPool *mp = cfg->mp;
1260 MonoBytecodeInfo *bcinfo = cfg->bcinfo;
1261 MonoMethodHeader *header;
1262 MonoMethodSignature *signature;
1265 MBTree **sp, **stack, **arg_sp, *t1, *t2, *t3;
1266 register const unsigned char *ip, *end;
1268 int i, j, depth, repeat_count;
1269 int varnum = 0, firstarg = 0, retvtarg = 0;
1270 gboolean repeat, superblock_end;
1271 MonoBBlock *bb, *tbb;
1273 header = ((MonoMethodNormal *)method)->header;
1274 signature = method->signature;
1275 image = method->klass->image;
1277 sp = stack = alloca (sizeof (MBTree *) * (header->max_stack + 1));
1279 if (header->num_locals) {
1282 for (i = 0; i < header->num_locals; ++i) {
1283 size = mono_type_size (header->locals [i], &align);
1284 varnum = arch_allocate_var (cfg, size, align, MONO_LOCALVAR, VAL_UNKNOWN);
1288 if (signature->ret->type == MONO_TYPE_VALUETYPE) {
1291 size = mono_type_size (signature->ret, &align);
1293 retvtarg = varnum = arch_allocate_var (cfg, size, align, MONO_LOCALVAR, VAL_UNKNOWN);
1295 //printf ("VALUETYPE METHOD %s.%s::%s %d\n", method->klass->name_space,
1296 //method->klass->name, method->name, size);
1299 firstarg = varnum + 1;
1301 if (signature->params_size) {
1303 int has_this = signature->hasthis;
1306 size = align = sizeof (gpointer);
1307 arch_allocate_var (cfg, size, align, MONO_ARGVAR, VAL_POINTER);
1310 for (i = 0; i < signature->param_count; ++i) {
1311 size = mono_type_size (signature->params [i], &align);
1316 arch_allocate_var (cfg, size, align, MONO_ARGVAR, VAL_UNKNOWN);
1324 superblock_end = TRUE;
1327 //printf ("START\n");
1328 for (i = 0; i < cfg->block_count; i++) {
1329 bb = &cfg->bblocks [i];
1331 //printf ("BBS %d %d %d %d\n", i, bb->reached, bb->finished, superblock_end);
1333 if (!bb->reached && !superblock_end) {
1334 MonoBBlock *sbb = &cfg->bblocks [i - 1];
1336 g_assert (sbb->outdepth == (sp - stack));
1338 mark_reached (cfg, bb, sbb->outstack, sbb->outdepth);
1343 if (!bb->finished) {
1347 for (j = 0; j < bb->indepth; j++) {
1348 sp [j] = bb->instack [j];
1354 ip = header->code + bb->cli_addr;
1355 end = ip + bb->length;
1357 bb->forest = forest = g_ptr_array_new ();
1359 superblock_end = FALSE;
1362 guint32 cli_addr = ip - header->code;
1364 //printf ("%d IL%04x OPCODE %s %d %d %d\n", i, cli_addr, opcode_names [*ip],
1365 //forest->len, superblock_end, sp - stack);
1374 t1 = mono_ctree_new_leaf (mp, MB_TERM_NOP);
1376 superblock_end = TRUE;
1385 token = read32 (ip);
1388 c = mono_class_get (image, token);
1390 t1 = mono_ctree_new_leaf (mp, MB_TERM_NEWOBJ);
1392 t1->svt = VAL_POINTER;
1394 t1 = mono_store_tree (cfg, -1, t1, &t3);
1398 t1 = ctree_create_dup (mp, t3);
1399 t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1400 t2->data.i = sizeof (MonoObject);
1401 t1 = mono_ctree_new (mp, MB_TERM_ADD, t1, t2);
1403 t1 = mono_ctree_new (mp, map_stvalue_type (c), t1, *sp);
1406 PUSH_TREE (t3, VAL_POINTER);
1414 token = read32 (ip);
1418 // fixme: add type check
1420 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1421 t1->data.i = sizeof (MonoObject);
1422 t1 = mono_ctree_new (mp, MB_TERM_ADD, *sp, t1);
1424 PUSH_TREE (t1, VAL_POINTER);
1431 t1 = mono_ctree_new (mp, MB_TERM_LDLEN, *sp, NULL);
1432 PUSH_TREE (t1, VAL_I32);
1441 token = read32 (ip);
1445 c = mono_class_get (image, token);
1446 g_assert (c->valuetype);
1448 t1 = ctree_create_load (cfg, &c->byval_arg, *sp, &svt);
1449 PUSH_TREE (t1, svt);
1457 index = mono_metadata_token_index (read32 (ip));
1460 o = (MonoObject *) mono_ldstr (image, index);
1461 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1464 PUSH_TREE (t1, VAL_POINTER);
1470 MonoClassField *field;
1472 int load_addr = *ip == CEE_LDSFLDA;
1476 token = read32 (ip);
1479 /* need to handle fieldrefs */
1480 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF |
1481 mono_metadata_typedef_from_field (image, token & 0xffffff));
1484 mono_jit_init_class (klass);
1486 field = mono_class_get_field (klass, token);
1489 addr = MONO_CLASS_STATIC_FIELDS_BASE (klass) + field->offset;
1492 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
1496 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
1498 t1 = ctree_create_load (cfg, field->type, t1, &svt);
1501 PUSH_TREE (t1, svt);
1507 MonoClassField *field;
1509 int load_addr = *ip == CEE_LDFLDA;
1512 token = read32 (ip);
1516 /* need to handle fieldrefs */
1517 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF |
1518 mono_metadata_typedef_from_field (image, token & 0xffffff));
1521 mono_jit_init_class (klass);
1523 field = mono_class_get_field (klass, token);
1526 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1528 if (klass->valuetype)
1529 t1->data.i = field->offset - sizeof (MonoObject);
1531 t1->data.i = field->offset;
1533 t1 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], t1);
1536 t1 = mono_ctree_new (mp, map_ldind_type (field->type, &svt), t1, NULL);
1540 PUSH_TREE (t1, svt);
1545 MonoClassField *field;
1550 token = read32 (ip);
1554 /* need to handle fieldrefs */
1555 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF |
1556 mono_metadata_typedef_from_field (image, token & 0xffffff));
1559 mono_jit_init_class (klass);
1561 field = mono_class_get_field (klass, token);
1564 addr = MONO_CLASS_STATIC_FIELDS_BASE (klass) + field->offset;
1565 t1 = ctree_create_store (mp, MB_TERM_ADDR_G, *sp, field->type, addr);
1572 MonoClassField *field;
1576 token = read32 (ip);
1580 /* need to handle fieldrefs */
1581 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF |
1582 mono_metadata_typedef_from_field (image, token & 0xffffff));
1585 mono_jit_init_class (klass);
1587 field = mono_class_get_field (klass, token);
1590 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1591 if (klass->valuetype)
1592 t1->data.i = field->offset - sizeof (MonoObject);
1594 t1->data.i = field->offset;
1596 //printf ("VALUETYPE %d %d %d\n", klass->valuetype, field->offset, t1->data.i);
1598 t1 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], t1);
1599 t1 = mono_ctree_new (mp, map_stind_type (field->type), t1, sp [1]);
1606 guint32 esize, token;
1609 token = read32 (ip);
1613 class = mono_class_get (image, token);
1616 mono_jit_init_class (class);
1618 esize = mono_class_instance_size (class);
1619 if (class->valuetype)
1620 esize -= sizeof (MonoObject);
1622 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1624 t1 = mono_ctree_new (mp, MB_TERM_MUL, sp [1], t1);
1625 t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1626 t2->data.i = G_STRUCT_OFFSET (MonoArray, vector);
1627 t2 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], t2);
1628 t1 = mono_ctree_new (mp, MB_TERM_ADD, t1, t2);
1630 PUSH_TREE (t1, VAL_POINTER);
1639 t1 = mono_ctree_new_leaf (mp, MB_TERM_BREAK);
1653 t1 = mono_ctree_new (mp, MB_TERM_SWITCH, *sp, NULL);
1654 jt = t1->data.p = mono_alloc_static (sizeof (gpointer) * (n + 2));
1655 st = cli_addr + 5 + 4 * n;
1657 // hack: we store n at position 0
1658 jt [0] = (MonoBBlock *)n;
1660 create_outstack (cfg, bb, stack, sp - stack);
1662 for (i = 1; i <= (n + 1); i++) {
1666 target = read32 (ip) + st;
1669 g_assert (target >= 0 && target <= header->code_size);
1670 g_assert (bcinfo [target].is_block_start);
1671 tbb = &cfg->bblocks [bcinfo [target].block_id];
1672 mark_reached (cfg, tbb, stack, sp - stack);
1681 MonoClass *handle_class;
1684 handle = mono_ldtoken (image, read32 (ip), &handle_class);
1687 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1688 t1->data.p = handle;
1689 PUSH_TREE (t1, VAL_POINTER);
1699 token = read32 (ip);
1700 class = mono_class_get (image, token);
1703 t1 = mono_ctree_new (mp, MB_TERM_NEWARR, *sp, NULL);
1705 PUSH_TREE (t1, VAL_POINTER);
1714 token = read32 (ip);
1715 class = mono_class_get (image, token);
1719 t1 = mono_ctree_new (mp, MB_TERM_CPOBJ, sp [0], sp [1]);
1725 MonoMethodSignature *csig;
1728 MBTree *this = NULL;
1730 int i, align, size, args_size = 0;
1734 token = read32 (ip);
1737 cm = mono_get_method (image, token, NULL);
1739 g_assert (!strcmp (cm->name, ".ctor"));
1741 ci = mono_mempool_alloc0 (mp, sizeof (MethodCallInfo));
1744 csig = cm->signature;
1745 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
1746 g_assert (csig->hasthis);
1748 arg_sp = sp -= csig->param_count;
1750 if (cm->klass->parent == mono_defaults.array_class) {
1752 this = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1755 this = mono_ctree_new_leaf (mp, MB_TERM_NEWOBJ);
1756 this->data.p = cm->klass;
1757 this->svt = VAL_POINTER;
1759 t1 = mono_store_tree (cfg, -1, this, &this);
1764 for (i = csig->param_count - 1; i >= 0; i--) {
1765 t1 = mono_ctree_new (mp, MB_TERM_ARG, arg_sp [i], NULL);
1767 size = mono_type_size (cm->signature->params [i], &align);
1768 args_size += (size + 3) & ~3;
1771 args_size += sizeof (gpointer); /* this argument */
1772 ci->args_size = args_size;
1776 t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1777 t2->data.p = mono_array_new_va;
1779 t1 = mono_ctree_new (mp, MB_TERM_CALL_I4, this, t2);
1781 t1->svt = VAL_POINTER;
1783 t1 = mono_store_tree (cfg, -1, t1, &t2);
1786 PUSH_TREE (t2, t2->svt);
1791 cm->addr = arch_create_simple_jit_trampoline (cm);
1793 t2 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
1794 t2->data.p = (char *)cm + G_STRUCT_OFFSET (MonoMethod, addr);
1795 t2 = mono_ctree_new (mp, MB_TERM_LDIND_I4, t2, NULL);
1797 t1 = mono_ctree_new (mp, map_call_type (csig->ret, &svt), this, t2);
1802 t1 = ctree_create_dup (mp, this);
1803 PUSH_TREE (t1, t1->svt);
1809 case CEE_CALLVIRT: {
1810 MonoMethodSignature *csig;
1813 MBTree *this = NULL;
1815 int i, align, size, args_size = 0;
1816 int virtual = *ip == CEE_CALLVIRT;
1817 gboolean array_set = FALSE;
1818 gboolean array_get = FALSE;
1819 gboolean pinvoke = FALSE;
1820 int nargs, vtype_num = 0;
1823 token = read32 (ip);
1826 cm = mono_get_method (image, token, NULL);
1829 ci = mono_mempool_alloc0 (mp, sizeof (MethodCallInfo));
1832 if (cm->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1835 if ((cm->flags & METHOD_ATTRIBUTE_FINAL) ||
1836 !(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
1839 csig = cm->signature;
1840 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
1841 g_assert (!virtual || csig->hasthis);
1843 /* fixme: we need to unbox the this pointer for value types */
1844 g_assert (!virtual || !cm->klass->valuetype);
1846 nargs = csig->param_count;
1847 arg_sp = sp -= nargs;
1849 if ((cm->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
1850 (cm->klass->parent == mono_defaults.array_class)) {
1851 if (!strcmp (cm->name, "Set")) {
1854 } else if (!strcmp (cm->name, "Get"))
1858 for (i = nargs - 1; i >= 0; i--) {
1859 if (pinvoke && cm->signature->params [i]->type == MONO_TYPE_STRING) {
1860 t1 = mono_ctree_new (mp, MB_TERM_STRING_ARG, arg_sp [i], NULL);
1862 t1 = mono_ctree_new (mp, MB_TERM_ARG, arg_sp [i], NULL);
1865 size = mono_type_size (cm->signature->params [i], &align);
1866 args_size += (size + 3) & ~3;
1869 if (csig->hasthis) {
1871 args_size += sizeof (gpointer);
1873 this = mono_ctree_new_leaf (mp, MB_TERM_NOP);
1875 if (csig->ret->type == MONO_TYPE_VALUETYPE) {
1877 if ((size = mono_type_size (csig->ret, &align)) > 4 || size == 3)
1878 vtype_num = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, VAL_UNKNOWN);
1881 ci->args_size = args_size;
1882 ci->vtype_num = vtype_num;
1885 int size, align, vnum;
1887 t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1888 t2->data.p = ves_array_element_address;
1890 t1 = mono_ctree_new (mp, MB_TERM_CALL_I4, this, t2);
1893 t1 = mono_ctree_new (mp, map_ldind_type (csig->ret, &svt), t1, NULL);
1896 mono_get_val_sizes (t1->svt, &size, &align);
1897 vnum = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, svt);
1899 t2 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
1901 t1 = mono_ctree_new (mp, map_store_svt_type (svt), t2, t1);
1905 t1 = ctree_create_dup (mp, t1);
1906 PUSH_TREE (t1, t1->svt);
1908 } else if (array_set) {
1910 t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1911 t2->data.p = ves_array_element_address;
1913 t1 = mono_ctree_new (mp, MB_TERM_CALL_I4, this, t2);
1916 t1 = mono_ctree_new (mp, map_stind_type (csig->params [nargs]), t1, arg_sp [nargs]);
1922 if (!cm->klass->metadata_inited)
1923 mono_class_metadata_init (cm->klass);
1925 if (cm->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
1926 t2 = mono_ctree_new_leaf (mp, MB_TERM_INTF_ADDR);
1928 t2 = mono_ctree_new_leaf (mp, MB_TERM_VFUNC_ADDR);
1935 cm->addr = arch_create_simple_jit_trampoline (cm);
1937 t2 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
1938 t2->data.p = (char *)cm + G_STRUCT_OFFSET (MonoMethod, addr);
1939 t2 = mono_ctree_new (mp, MB_TERM_LDIND_I4, t2, NULL);
1942 t1 = mono_ctree_new (mp, map_call_type (csig->ret, &svt), this, t2);
1946 if (csig->ret->type != MONO_TYPE_VOID) {
1950 t1 = mono_ctree_new_leaf (mp, MB_TERM_VTYPE);
1951 t1->data.i = vtype_num;
1952 PUSH_TREE (t1, VAL_UNKNOWN);
1954 t1 = mono_store_tree (cfg, -1, t1, &t2);
1957 PUSH_TREE (t2, t2->svt);
1967 case CEE_CASTCLASS: {
1970 token = read32 (ip);
1972 /* fixme: do something */
1977 case CEE_LDC_I4_S: {
1979 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1980 t1->data.i = *(gint8 *)ip;
1982 PUSH_TREE (t1, VAL_I32);
1987 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1988 t1->data.i = read32 (ip);
1990 PUSH_TREE (t1, VAL_I32);
2002 case CEE_LDC_I4_8: {
2003 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2004 t1->data.i = (*ip) - CEE_LDC_I4_0;
2006 PUSH_TREE (t1, VAL_I32);
2010 //fixme: don't know if this is portable ?
2012 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2014 PUSH_TREE (t1, VAL_I32);
2019 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I8);
2020 t1->data.l = read64 (ip);
2022 PUSH_TREE (t1, VAL_I64);
2026 float *f = mono_alloc_static (sizeof (float));
2028 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_R4);
2032 PUSH_TREE (t1, VAL_DOUBLE);
2036 double *d = mono_alloc_static (sizeof (double));
2038 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_R8);
2042 PUSH_TREE (t1, VAL_DOUBLE);
2049 int n = (*ip) - CEE_LDLOC_0;
2052 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2053 t1->data.i = LOCAL_POS (n);
2054 t1 = ctree_create_load (cfg, LOCAL_TYPE (n), t1, &svt);
2056 PUSH_TREE (t1, svt);
2062 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2063 t1->data.i = LOCAL_POS (*ip);
2064 t1 = ctree_create_load (cfg, LOCAL_TYPE (*ip), t1, &svt);
2067 PUSH_TREE (t1, svt);
2070 case CEE_LDLOCA_S: {
2073 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2074 t1->data.p = (gpointer)LOCAL_POS (*ip);
2076 PUSH_TREE (t1, VAL_POINTER);
2083 int n = (*ip) - CEE_STLOC_0;
2087 t1 = ctree_create_store (mp, MB_TERM_ADDR_L, *sp, LOCAL_TYPE (n),
2088 (gpointer)LOCAL_POS (n));
2097 t1 = ctree_create_store (mp, MB_TERM_ADDR_L, *sp, LOCAL_TYPE (*ip),
2098 (gpointer)LOCAL_POS (*ip));
2112 MAKE_BI_ALU (SHR_UN)
2115 MAKE_BI_ALU (DIV_UN)
2117 MAKE_BI_ALU (REM_UN)
2119 MAKE_LDIND (LDIND_I1, MB_TERM_LDIND_I1, VAL_I32)
2120 MAKE_LDIND (LDIND_U1, MB_TERM_LDIND_U1, VAL_I32)
2121 MAKE_LDIND (LDIND_I2, MB_TERM_LDIND_I2, VAL_I32)
2122 MAKE_LDIND (LDIND_U2, MB_TERM_LDIND_U2, VAL_I32)
2123 MAKE_LDIND (LDIND_I, MB_TERM_LDIND_I4, VAL_I32)
2124 MAKE_LDIND (LDIND_I4, MB_TERM_LDIND_I4, VAL_I32)
2125 MAKE_LDIND (LDIND_REF, MB_TERM_LDIND_U4, VAL_I32)
2126 MAKE_LDIND (LDIND_U4, MB_TERM_LDIND_U4, VAL_I32)
2127 MAKE_LDIND (LDIND_I8, MB_TERM_LDIND_I8, VAL_I64)
2128 MAKE_LDIND (LDIND_R4, MB_TERM_LDIND_R4, VAL_DOUBLE)
2129 MAKE_LDIND (LDIND_R8, MB_TERM_LDIND_R8, VAL_DOUBLE)
2131 MAKE_STIND (STIND_I1, MB_TERM_STIND_I1)
2132 MAKE_STIND (STIND_I2, MB_TERM_STIND_I2)
2133 MAKE_STIND (STIND_I, MB_TERM_STIND_I4)
2134 MAKE_STIND (STIND_I4, MB_TERM_STIND_I4)
2135 MAKE_STIND (STIND_I8, MB_TERM_STIND_I8)
2136 MAKE_STIND (STIND_R4, MB_TERM_STIND_R4)
2137 MAKE_STIND (STIND_R8, MB_TERM_STIND_R8)
2138 MAKE_STIND (STIND_REF, MB_TERM_STIND_I4)
2140 MAKE_LDELEM (LDELEM_I1, MB_TERM_LDIND_I1, VAL_I32, 1)
2141 MAKE_LDELEM (LDELEM_U1, MB_TERM_LDIND_U1, VAL_I32, 1)
2142 MAKE_LDELEM (LDELEM_I2, MB_TERM_LDIND_I2, VAL_I32, 2)
2143 MAKE_LDELEM (LDELEM_U2, MB_TERM_LDIND_U2, VAL_I32, 2)
2144 MAKE_LDELEM (LDELEM_I, MB_TERM_LDIND_I4, VAL_I32, 4)
2145 MAKE_LDELEM (LDELEM_I4, MB_TERM_LDIND_I4, VAL_I32, 4)
2146 MAKE_LDELEM (LDELEM_REF, MB_TERM_LDIND_U4, VAL_I32, 4)
2147 MAKE_LDELEM (LDELEM_U4, MB_TERM_LDIND_U4, VAL_I32, 4)
2148 MAKE_LDELEM (LDELEM_I8, MB_TERM_LDIND_I8, VAL_I64, 8)
2149 MAKE_LDELEM (LDELEM_R4, MB_TERM_LDIND_R4, VAL_DOUBLE, 4)
2150 MAKE_LDELEM (LDELEM_R8, MB_TERM_LDIND_R8, VAL_DOUBLE, 8)
2152 MAKE_STELEM (STELEM_I1, MB_TERM_STIND_I1, 1)
2153 MAKE_STELEM (STELEM_I2, MB_TERM_STIND_I2, 2)
2154 MAKE_STELEM (STELEM_I4, MB_TERM_STIND_I4, 4)
2155 MAKE_STELEM (STELEM_I, MB_TERM_STIND_I4, 4)
2156 MAKE_STELEM (STELEM_REF, MB_TERM_STIND_I4, 4)
2157 MAKE_STELEM (STELEM_I8, MB_TERM_STIND_I8, 8)
2158 MAKE_STELEM (STELEM_R4, MB_TERM_STIND_R4, 4)
2159 MAKE_STELEM (STELEM_R8, MB_TERM_STIND_R8, 8)
2164 t1 = mono_ctree_new (mp, MB_TERM_NEG, sp [0], NULL);
2165 PUSH_TREE (t1, sp [0]->svt);
2171 t1 = mono_ctree_new (mp, MB_TERM_NOT, sp [0], NULL);
2172 PUSH_TREE (t1, sp [0]->svt);
2179 t1 = mono_ctree_new_leaf (mp, MB_TERM_BR);
2180 target = cli_addr + 2 + (signed char) *ip;
2182 g_assert (target >= 0 && target <= header->code_size);
2183 g_assert (bcinfo [target].is_block_start);
2184 tbb = &cfg->bblocks [bcinfo [target].block_id];
2185 create_outstack (cfg, bb, stack, sp - stack);
2186 mark_reached (cfg, tbb, bb->outstack, bb->outdepth);
2192 superblock_end = TRUE;
2199 t1 = mono_ctree_new_leaf (mp, MB_TERM_BR);
2200 target = cli_addr + 5 + (gint32) read32(ip);
2202 g_assert (target >= 0 && target <= header->code_size);
2203 g_assert (bcinfo [target].is_block_start);
2204 tbb = &cfg->bblocks [bcinfo [target].block_id];
2205 create_outstack (cfg, bb, stack, sp - stack);
2206 mark_reached (cfg, tbb, bb->outstack, bb->outdepth);
2212 superblock_end = TRUE;
2228 case CEE_BRTRUE_S: {
2230 int near_jump = *ip == CEE_BRTRUE_S;
2234 t1 = mono_ctree_new (mp, MB_TERM_BRTRUE, sp [0], NULL);
2237 target = cli_addr + 2 + (signed char) *ip;
2239 target = cli_addr + 5 + (gint32) read32 (ip);
2241 g_assert (target >= 0 && target <= header->code_size);
2242 g_assert (bcinfo [target].is_block_start);
2243 tbb = &cfg->bblocks [bcinfo [target].block_id];
2244 create_outstack (cfg, bb, stack, sp - stack);
2245 mark_reached (cfg, tbb, bb->outstack, bb->outdepth);
2248 ip += near_jump ? 1: 4;
2253 case CEE_BRFALSE_S: {
2255 int near_jump = *ip == CEE_BRFALSE_S;
2259 t1 = mono_ctree_new (mp, MB_TERM_BRFALSE, sp [0], NULL);
2262 target = cli_addr + 2 + (signed char) *ip;
2264 target = cli_addr + 5 + (gint32) read32 (ip);
2266 g_assert (target >= 0 && target <= header->code_size);
2267 g_assert (bcinfo [target].is_block_start);
2268 tbb = &cfg->bblocks [bcinfo [target].block_id];
2269 create_outstack (cfg, bb, stack, sp - stack);
2270 mark_reached (cfg, tbb, bb->outstack, bb->outdepth);
2273 ip += near_jump ? 1: 4;
2280 if (signature->ret->type != MONO_TYPE_VOID) {
2282 t1 = mono_ctree_new (mp, MB_TERM_RETV, *sp, NULL);
2284 t1 = mono_ctree_new (mp, MB_TERM_RET, NULL, NULL);
2287 t1->last_instr = (ip == end);
2292 g_warning ("more values on stack at IL_%04x: %d", ip - header->code, sp - stack);
2293 mono_print_ctree (sp [-1]);
2296 superblock_end = TRUE;
2303 int n = (*ip) - CEE_LDARG_0;
2306 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2307 t1->data.i = ARG_POS (n);
2308 t1 = ctree_create_load (cfg, ARG_TYPE (n), t1, &svt);
2309 PUSH_TREE (t1, svt);
2315 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2316 t1->data.i = ARG_POS (*ip);
2317 t1 = ctree_create_load (cfg, ARG_TYPE (*ip), t1, &svt);
2318 PUSH_TREE (t1, svt);
2322 case CEE_LDARGA_S: {
2325 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2326 t1->data.i = ARG_POS (*ip);
2327 PUSH_TREE (t1, VAL_POINTER);
2335 t1 = ctree_create_store (mp, MB_TERM_ADDR_L, *sp, ARG_TYPE (*ip),
2336 (gpointer)ARG_POS (*ip));
2345 /* fixme: IMO we can use the temp. variable associated
2346 * with the current slot instead of -1
2348 if ((t2 = mono_store_tree (cfg, -1, *sp, &t1)) != NULL)
2351 PUSH_TREE (t1, t1->svt);
2352 t1 = ctree_create_dup (mp, t1);
2353 PUSH_TREE (t1, t1->svt);
2361 t1 = mono_ctree_new (mp, MB_TERM_POP, *sp, NULL);
2370 t1 = mono_ctree_new (mp, MB_TERM_CONV_I1, *sp, NULL);
2371 PUSH_TREE (t1, VAL_I32);
2378 t1 = mono_ctree_new (mp, MB_TERM_CONV_I2, *sp, NULL);
2379 PUSH_TREE (t1, VAL_I32);
2388 t1 = mono_ctree_new (mp, MB_TERM_CONV_I4, *sp, NULL);
2389 PUSH_TREE (t1, VAL_I32);
2395 t1 = mono_ctree_new (mp, MB_TERM_CONV_I8, *sp, NULL);
2396 PUSH_TREE (t1, VAL_I64);
2402 t1 = mono_ctree_new (mp, MB_TERM_CONV_I8, *sp, NULL);
2403 PUSH_TREE (t1, VAL_I64);
2409 t1 = mono_ctree_new (mp, MB_TERM_CONV_R8, *sp, NULL);
2410 PUSH_TREE (t1, VAL_DOUBLE);
2413 case CEE_CONV_OVF_U4: {
2414 // fixme: raise exceptions ?
2417 t1 = mono_ctree_new (mp, MB_TERM_CONV_I4, *sp, NULL);
2418 PUSH_TREE (t1, VAL_I32);
2421 case CEE_CONV_OVF_I4_UN: {
2422 // fixme: raise exceptions ?
2425 t1 = mono_ctree_new (mp, MB_TERM_CONV_I4, *sp, NULL);
2426 PUSH_TREE (t1, VAL_I32);
2429 case CEE_CONV_OVF_U4_UN: {
2430 // fixme: raise exceptions ?
2433 t1 = mono_ctree_new (mp, MB_TERM_CONV_I4, *sp, NULL);
2434 PUSH_TREE (t1, VAL_I32);
2449 token = read32 (ip);
2450 class = mono_class_get (image, token);
2454 t1 = mono_ctree_new (mp, MB_TERM_INITOBJ, *sp, NULL);
2455 t1->data.i = mono_class_value_size (class, NULL);
2466 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2467 t1->data.i = ARG_POS (n);
2468 t1 = ctree_create_load (cfg, ARG_TYPE (n), t1, &svt);
2469 PUSH_TREE (t1, svt);
2473 g_error ("Unimplemented opcode at IL_%04x "
2474 "0xFE %02x", ip - header->code, *ip);
2479 g_warning ("unknown instruction `%s' at IL_%04X",
2480 opcode_names [*ip], ip - header->code);
2481 mono_print_forest (forest);
2482 g_assert_not_reached ();
2486 if ((depth = sp - stack)) {
2487 create_outstack (cfg, bb, stack, sp - stack);
2488 //mono_print_forest (forest);
2489 //printf ("DEPTH %d %d\n", depth, sp [0]->op);
2493 superblock_end = TRUE;
2496 superblock_end = TRUE;
2497 //printf ("unreached block %d\n", i);
2499 g_assert (repeat_count < 10);
2501 //printf ("BBE %d %d %d %d\n", i, bb->reached, bb->finished, superblock_end);
2505 //printf ("REPEAT %d\n", repeat);
2510 //printf ("FINISHED\n");
2513 /* this function is never called */
2515 ves_array_set (MonoArray *this, ...)
2517 g_assert_not_reached ();
2520 /* this function is never called */
2522 ves_array_get (MonoArray *this, ...)
2524 g_assert_not_reached ();
2528 * mono_jit_assembly:
2529 * @assembly: reference to an assembly
2531 * JIT compilation of all methods in the assembly. Prints debugging
2532 * information on stdout.
2535 mono_jit_assembly (MonoAssembly *assembly)
2537 MonoImage *image = assembly->image;
2539 MonoTableInfo *t = &image->tables [MONO_TABLE_METHOD];
2542 for (i = 0; i < t->rows; i++) {
2544 method = mono_get_method (image,
2545 (MONO_TABLE_METHOD << 24) | (i + 1),
2548 printf ("\nMethod: %s\n\n", method->name);
2550 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
2551 printf ("ABSTARCT\n");
2553 arch_compile_method (method);
2559 typedef int (*MonoMainIntVoid) ();
2563 * @assembly: reference to an assembly
2564 * @argc: argument count
2565 * @argv: argument vector
2567 * Start execution of a program.
2570 mono_jit_exec (MonoAssembly *assembly, int argc, char *argv[])
2572 MonoImage *image = assembly->image;
2573 MonoCLIImageInfo *iinfo;
2577 iinfo = image->image_info;
2578 method = mono_get_method (image, iinfo->cli_cli_header.ch_entry_point, NULL);
2580 if (method->signature->param_count) {
2581 g_warning ("Main () with arguments not yet supported");
2584 MonoMainIntVoid mfunc;
2586 mfunc = arch_compile_method (method);
2597 "%s %s, the Mono ECMA CLI JIT Compiler, (C) 2001 Ximian, Inc.\n\n"
2598 "Usage is: %s [options] executable args...\n", name, VERSION, name);
2600 "Valid Options are:\n"
2601 "-d debug the jit, show disassembler output.\n"
2602 "--dump-asm dumps the assembly code generated\n"
2603 "--dump-forest dumps the reconstructed forest\n"
2604 "--trace-calls printf function call trace\n"
2605 "--help print this help message\n");
2610 main (int argc, char *argv [])
2612 MonoAssembly *assembly;
2615 gboolean testjit = FALSE;
2620 for (i = 1; i < argc && argv [i][0] == '-'; i++){
2621 if (strcmp (argv [i], "--help") == 0) {
2623 } else if (strcmp (argv [i], "-d") == 0) {
2625 mono_jit_dump_asm = TRUE;
2626 mono_jit_dump_forest = TRUE;
2627 } else if (strcmp (argv [i], "--dump-asm") == 0)
2628 mono_jit_dump_asm = TRUE;
2629 else if (strcmp (argv [i], "--dump-forest") == 0)
2630 mono_jit_dump_forest = TRUE;
2631 else if (strcmp (argv [i], "--trace-calls") == 0)
2632 mono_jit_trace_calls = TRUE;
2644 mono_add_internal_call ("__array_Set", ves_array_set);
2645 mono_add_internal_call ("__array_Get", ves_array_get);
2647 mono_install_trampoline (arch_create_jit_trampoline);
2649 assembly = mono_assembly_open (file, NULL, NULL);
2651 fprintf (stderr, "Can not open image %s\n", file);
2656 mono_jit_assembly (assembly);
2658 retval = mono_jit_exec (assembly, argc, argv);
2659 printf ("RESULT: %d\n", retval);
2662 mono_assembly_close (assembly);