2 * testjit.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>
43 * Pull the list of opcodes
45 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
49 #include "mono/cil/opcode.def"
54 #define OPDEF(a,b,c,d,e,f,g,h,i,j) b,
55 static char *opcode_names [] = {
56 #include "mono/cil/opcode.def"
60 #define SET_VARINFO(vi,t,k,o,s) do { vi.type=t; vi.kind=k; vi.offset=o; vi.size=s; } while (0)
62 #define MAKE_CJUMP(name) \
64 case CEE_##name##_S: { \
66 int near_jump = *ip == CEE_##name##_S; \
69 t1 = mono_ctree_new (mp, MB_TERM_##name, sp [0], sp [1]); \
71 target = cli_addr + 2 + (signed char) *ip; \
73 target = cli_addr + 5 + (gint32) read32 (ip); \
74 g_assert (target >= 0 && target <= header->code_size); \
75 g_assert (bcinfo [target].is_block_start); \
76 tbb = &cfg->bblocks [bcinfo [target].block_id]; \
77 create_outstack (cfg, bb, stack, sp - stack); \
78 mark_reached (cfg, tbb, bb->outstack, bb->outdepth); \
80 ADD_TREE (t1, cli_addr); \
81 ip += near_jump ? 1: 4; \
85 #define MAKE_BI_ALU(name) \
89 t1 = mono_ctree_new (mp, MB_TERM_##name, sp [0], sp [1]); \
90 PUSH_TREE (t1, sp [0]->svt); \
94 #define MAKE_CMP(cname) \
98 t1 = mono_ctree_new (mp, MB_TERM_##cname, sp [0], sp [1]); \
99 PUSH_TREE (t1, VAL_I32); \
103 #define MAKE_SPILLED_BI_ALU(name) \
107 t1 = mono_ctree_new (mp, MB_TERM_##name, sp [0], sp [1]); \
108 t1->svt = sp [0]->svt; \
109 t1 = mono_store_tree (cfg, -1, t1, &t2); \
111 ADD_TREE (t1, cli_addr); \
112 PUSH_TREE (t2, t2->svt); \
116 #define MAKE_LDIND(name, op, svt) \
120 t1 = mono_ctree_new (mp, op, *sp, NULL); \
121 PUSH_TREE (t1, svt); \
125 #define MAKE_LDELEM(name, op, svt, s) \
129 t1 = mono_ctree_new (mp, MB_TERM_LDELEMA, sp [0], sp [1]); \
131 t1 = mono_ctree_new (mp, op, t1, NULL); \
132 PUSH_TREE (t1, svt); \
136 #define MAKE_LDELEM_OLD(name, op, svt, s) \
140 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4); \
142 t1 = mono_ctree_new (mp, MB_TERM_MUL, sp [1], t1); \
143 t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4); \
144 t2->data.i = G_STRUCT_OFFSET (MonoArray, vector); \
145 t2 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], t2); \
146 t1 = mono_ctree_new (mp, MB_TERM_ADD, t1, t2); \
147 t1 = mono_ctree_new (mp, op, t1, NULL); \
148 PUSH_TREE (t1, svt); \
152 #define MAKE_STIND(name, op) \
156 t1 = mono_ctree_new (mp, op, sp [0], sp [1]); \
157 ADD_TREE (t1, cli_addr); \
161 #define MAKE_STELEM(name, op, s) \
165 t1 = mono_ctree_new (mp, MB_TERM_LDELEMA, sp [0], sp [1]); \
167 t1 = mono_ctree_new (mp, op, t1, sp [2]); \
168 ADD_TREE (t1, cli_addr); \
172 #define MAKE_STELEM_OLD(name, op, s) \
176 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4); \
178 t1 = mono_ctree_new (mp, MB_TERM_MUL, sp [1], t1); \
179 t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4); \
180 t2->data.i = G_STRUCT_OFFSET (MonoArray, vector); \
181 t2 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], t2); \
182 t1 = mono_ctree_new (mp, MB_TERM_ADD, t1, t2); \
183 t1 = mono_ctree_new (mp, op, t1, sp [2]); \
184 ADD_TREE (t1, cli_addr); \
188 /* Whether to dump the assembly code after genreating it */
189 gboolean mono_jit_dump_asm = FALSE;
191 /* Whether to dump the forest */
192 gboolean mono_jit_dump_forest = FALSE;
194 /* Whether to print function call traces */
195 gboolean mono_jit_trace_calls = FALSE;
197 /* Force jit to share code between application domains */
198 gboolean mono_jit_share_code = FALSE;
200 /* maximum number of worker threads */
201 int mono_worker_threads = 1;
203 MonoDebugHandle *mono_debug_handle = NULL;
204 GList *mono_debug_methods = NULL;
206 gpointer mono_end_of_stack = NULL;
208 /* last managed frame (used by pinvoke) */
209 guint32 lmf_thread_id = 0;
211 /* used to store a function pointer called after uncatched exceptions */
212 guint32 exc_cleanup_id = 0;
214 /* stores a pointer to async result used by exceptions */
215 guint32 async_result_id = 0;
217 MonoJitStats mono_jit_stats;
219 CRITICAL_SECTION *metadata_section = NULL;
222 * We sometimes need static data, for example the forest generator need it to
223 * store constants or class data.
225 inline static gpointer
226 mono_alloc_static (int size)
228 return g_malloc (size);
230 inline static gpointer
231 mono_alloc_static0 (int size)
233 return g_malloc0 (size);
236 typedef void (*MonoCCtor) (void);
239 * runtime_class_init:
240 * @klass: the class to initialise
242 * Initialise the class @klass by calling the class constructor.
245 runtime_class_init (MonoClass *klass)
251 if (mono_debug_handle)
252 mono_debug_add_type (mono_debug_handle, klass);
254 for (i = 0; i < klass->method.count; ++i) {
255 method = klass->methods [i];
256 if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
257 (strcmp (".cctor", method->name) == 0)) {
259 cctor = arch_compile_method (method);
260 if (!cctor && mono_debug_handle)
262 g_assert (cctor != NULL);
267 /* No class constructor found */
271 map_store_svt_type (int svt)
275 return MB_TERM_STIND_I4;
277 return MB_TERM_STIND_REF;
279 return MB_TERM_STIND_I8;
281 return MB_TERM_STIND_R8;
283 g_assert_not_reached ();
291 * @type: the type to map
293 * Translates the MonoType @type into the corresponding store opcode
294 * for the code generator.
297 map_stind_type (MonoType *type)
300 return MB_TERM_STIND_REF;
302 switch (type->type) {
305 case MONO_TYPE_BOOLEAN:
306 return MB_TERM_STIND_I1;
310 return MB_TERM_STIND_I2;
314 return MB_TERM_STIND_I4;
315 case MONO_TYPE_CLASS:
316 case MONO_TYPE_OBJECT:
317 case MONO_TYPE_STRING:
319 case MONO_TYPE_SZARRAY:
320 case MONO_TYPE_ARRAY:
321 return MB_TERM_STIND_REF;
324 return MB_TERM_STIND_I8;
326 return MB_TERM_STIND_R4;
328 return MB_TERM_STIND_R8;
329 case MONO_TYPE_VALUETYPE:
330 if (type->data.klass->enumtype)
331 return map_stind_type (type->data.klass->enum_basetype);
333 return MB_TERM_STIND_OBJ;
335 g_warning ("unknown type %02x", type->type);
336 g_assert_not_reached ();
339 g_assert_not_reached ();
344 map_starg_type (MonoType *type)
347 return MB_TERM_STIND_REF;
349 switch (type->type) {
352 case MONO_TYPE_BOOLEAN:
359 return MB_TERM_STIND_I4;
360 case MONO_TYPE_CLASS:
361 case MONO_TYPE_OBJECT:
362 case MONO_TYPE_STRING:
364 case MONO_TYPE_SZARRAY:
365 case MONO_TYPE_ARRAY:
366 return MB_TERM_STIND_REF;
369 return MB_TERM_STIND_I8;
371 return MB_TERM_STIND_R4;
373 return MB_TERM_STIND_R8;
374 case MONO_TYPE_VALUETYPE:
375 if (type->data.klass->enumtype)
376 return map_starg_type (type->data.klass->enum_basetype);
378 return MB_TERM_STIND_OBJ;
380 g_warning ("unknown type %02x", type->type);
381 g_assert_not_reached ();
384 g_assert_not_reached ();
389 map_arg_type (MonoType *type)
392 return MB_TERM_ARG_I4;
394 switch (type->type) {
397 case MONO_TYPE_BOOLEAN:
405 case MONO_TYPE_CLASS:
406 case MONO_TYPE_OBJECT:
408 case MONO_TYPE_SZARRAY:
409 case MONO_TYPE_ARRAY:
410 return MB_TERM_ARG_I4;
411 case MONO_TYPE_STRING:
412 return MB_TERM_ARG_I4;
415 return MB_TERM_ARG_I8;
417 return MB_TERM_ARG_R4;
419 return MB_TERM_ARG_R8;
420 case MONO_TYPE_VALUETYPE:
421 if (type->data.klass->enumtype)
422 return map_arg_type (type->data.klass->enum_basetype);
424 return MB_TERM_ARG_OBJ;
426 g_warning ("unknown type %02x", type->type);
427 g_assert_not_reached ();
430 g_assert_not_reached ();
436 * @type: the type to map
438 * Translates the MonoType @type into the corresponding load opcode
439 * for the code generator.
442 map_ldind_type (MonoType *type, MonoValueType *svt)
446 return MB_TERM_LDIND_REF;
449 switch (type->type) {
452 return MB_TERM_LDIND_I1;
454 case MONO_TYPE_BOOLEAN:
456 return MB_TERM_LDIND_U1;
459 return MB_TERM_LDIND_I2;
463 return MB_TERM_LDIND_U2;
467 return MB_TERM_LDIND_I4;
470 return MB_TERM_LDIND_U4;
471 case MONO_TYPE_CLASS:
472 case MONO_TYPE_OBJECT:
473 case MONO_TYPE_STRING:
475 case MONO_TYPE_SZARRAY:
476 case MONO_TYPE_ARRAY:
478 return MB_TERM_LDIND_REF;
482 return MB_TERM_LDIND_I8;
485 return MB_TERM_LDIND_R4;
488 return MB_TERM_LDIND_R8;
489 case MONO_TYPE_VALUETYPE:
490 if (type->data.klass->enumtype) {
491 return map_ldind_type (type->data.klass->enum_basetype, svt);
494 return MB_TERM_LDIND_OBJ;
497 g_warning ("unknown type %02x", type->type);
498 g_assert_not_reached ();
501 g_assert_not_reached ();
506 map_ldarg_type (MonoType *type, MonoValueType *svt)
510 return MB_TERM_LDIND_REF;
513 switch (type->type) {
516 case MONO_TYPE_BOOLEAN:
524 return MB_TERM_LDIND_U4;
525 case MONO_TYPE_CLASS:
526 case MONO_TYPE_OBJECT:
527 case MONO_TYPE_STRING:
529 case MONO_TYPE_SZARRAY:
530 case MONO_TYPE_ARRAY:
532 return MB_TERM_LDIND_U4;
536 return MB_TERM_LDIND_I8;
539 return MB_TERM_LDIND_R4;
542 return MB_TERM_LDIND_R8;
543 case MONO_TYPE_VALUETYPE:
544 if (type->data.klass->enumtype) {
545 return map_ldarg_type (type->data.klass->enum_basetype, svt);
548 return MB_TERM_LDIND_OBJ;
551 g_warning ("unknown type %02x", type->type);
552 g_assert_not_reached ();
555 g_assert_not_reached ();
561 * @type: the type to map
563 * Translates the MonoType @type into the corresponding call opcode
564 * for the code generator.
567 map_call_type (MonoType *type, MonoValueType *svt)
570 return MB_TERM_CALL_I4;
572 switch (type->type) {
575 return MB_TERM_CALL_VOID;
578 case MONO_TYPE_BOOLEAN:
586 return MB_TERM_CALL_I4;
587 case MONO_TYPE_VALUETYPE:
588 if (type->data.klass->enumtype) {
589 return map_call_type (type->data.klass->enum_basetype, svt);
592 return MB_TERM_CALL_VOID;
594 case MONO_TYPE_CLASS:
595 case MONO_TYPE_OBJECT:
596 case MONO_TYPE_STRING:
598 case MONO_TYPE_SZARRAY:
600 return MB_TERM_CALL_I4;
604 return MB_TERM_CALL_I8;
608 return MB_TERM_CALL_R8;
610 g_warning ("unknown type %02x", type->type);
611 g_assert_not_reached ();
614 g_assert_not_reached ();
619 * prints the tree to stdout
622 mono_print_ctree (MBTree *tree)
629 arity = (tree->left != NULL) + (tree->right != NULL);
632 printf (" (%s", mono_burg_term_string [tree->op]);
634 printf (" %s", mono_burg_term_string [tree->op]);
638 printf ("[%d]", tree->data.i);
642 g_assert (!(tree->right && !tree->left));
644 mono_print_ctree (tree->left);
645 mono_print_ctree (tree->right);
652 * prints the whole forest to stdout
655 mono_print_forest (GPtrArray *forest)
657 const int top = forest->len;
660 for (i = 0; i < top; i++) {
661 MBTree *t = (MBTree *) g_ptr_array_index (forest, i);
663 mono_print_ctree (t);
670 * mono_disassemble_code:
671 * @code: a pointer to the code
672 * @size: the code size in bytes
674 * Disassemble to code to stdout.
677 mono_disassemble_code (guint8 *code, int size, char *id)
682 if (!(ofd = fopen ("/tmp/test.s", "w")))
683 g_assert_not_reached ();
685 fprintf (ofd, "%s:\n", id);
687 for (i = 0; i < size; ++i)
688 fprintf (ofd, ".byte %d\n", (unsigned int) code [i]);
692 system ("as /tmp/test.s -o /tmp/test.o;objdump -d /tmp/test.o");
696 arch_allocate_var (MonoFlowGraph *cfg, int size, int align, MonoValueKind kind, MonoValueType type)
700 mono_jit_stats.allocate_var++;
704 case MONO_LOCALVAR: {
705 cfg->locals_size += size;
706 cfg->locals_size += align - 1;
707 cfg->locals_size &= ~(align - 1);
709 SET_VARINFO (vi, type, kind, - cfg->locals_size, size);
710 g_array_append_val (cfg->varinfo, vi);
714 int arg_start = 8 + cfg->has_vtarg*4;
716 g_assert ((align & 3) == 0);
718 SET_VARINFO (vi, type, kind, cfg->args_size + arg_start, size);
719 g_array_append_val (cfg->varinfo, vi);
721 cfg->args_size += size;
723 cfg->args_size &= ~3;
727 g_assert_not_reached ();
730 return cfg->varinfo->len - 1;
734 mono_get_val_sizes (MonoValueType type, int *size, int *align)
738 *size = *align = sizeof (gint32);
741 *size = *align = sizeof (gint64);
744 *size = *align = sizeof (gpointer);
747 *size = *align = sizeof (double);
750 g_assert_not_reached ();
755 mono_allocate_intvar (MonoFlowGraph *cfg, int slot, MonoValueType type)
757 int size, align, vnum, pos;
759 g_assert (type != VAL_UNKNOWN);
761 /* take care if you modify MonoValueType */
762 g_assert (VAL_DOUBLE == 4);
764 /* fixme: machine dependant */
765 if (type == VAL_POINTER)
766 type = VAL_I32; /* VAL_I32 and VAL_POINTER share the same slot */
768 pos = type - 1 + slot * VAL_DOUBLE;
770 if ((vnum = cfg->intvars [pos]))
772 mono_get_val_sizes (type, &size, &align);
774 cfg->intvars[pos] = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, type);
776 return cfg->intvars[pos];
780 mono_allocate_excvar (MonoFlowGraph *cfg)
785 cfg->excvar = arch_allocate_var (cfg, 4, 4, MONO_TEMPVAR, VAL_POINTER);
793 * @cfg: pointer to the control flow graph
794 * @type: the type of the value to load
795 * @addr: the address of the value
797 * Creates a tree to load the value at address @addr.
799 inline static MBTree *
800 ctree_create_load (MonoFlowGraph *cfg, MonoType *type, MBTree *addr, MonoValueType *svt, gboolean arg)
802 MonoMemPool *mp = cfg->mp;
807 ldind = map_ldarg_type (type, svt);
809 ldind = map_ldind_type (type, svt);
811 t = mono_ctree_new (mp, ldind, addr, NULL);
817 * ctree_create_store:
818 * @mp: pointer to a memory pool
819 * @addr_type: address type (MB_TERM_ADDR_L or MB_TERM_ADDR_G)
820 * @s: the value (tree) to store
821 * @type: the type of the value
822 * @addr: the address of the value
824 * Creates a tree to store the value @s at address @addr.
826 inline static MBTree *
827 ctree_create_store (MonoFlowGraph *cfg, MonoType *type, MBTree *addr,
828 MBTree *s, gboolean arg)
830 MonoMemPool *mp = cfg->mp;
835 stind = map_starg_type (type);
837 stind = map_stind_type (type);
839 t = mono_ctree_new (mp, stind, addr, s);
842 t->data.i = mono_class_value_size (type->data.klass, NULL);
847 inline static MBTree *
848 ctree_dup_address (MonoMemPool *mp, MBTree *s)
856 t = mono_ctree_new_leaf (mp, s->op);
857 t->data.i = s->data.i;
858 t->svt = VAL_POINTER;
861 g_warning ("unknown tree opcode %d", s->op);
862 g_assert_not_reached ();
869 * Create a duplicate of the value of a tree. This is
870 * easy for trees starting with LDIND/STIND, since the
871 * duplicate is simple a LDIND tree with the same address.
872 * For other trees we have to split the tree into one tree
873 * storing the value to a new temporary variable, and
874 * another tree which loads that value back. We can then
875 * duplicate the second tree.
878 ctree_create_dup (MonoMemPool *mp, MBTree *s)
883 case MB_TERM_STIND_I1:
884 case MB_TERM_LDIND_I1:
885 t = ctree_dup_address (mp, s->left);
886 t = mono_ctree_new (mp, MB_TERM_LDIND_I1, t, NULL);
889 case MB_TERM_STIND_I2:
890 case MB_TERM_LDIND_I2:
891 t = ctree_dup_address (mp, s->left);
892 t = mono_ctree_new (mp, MB_TERM_LDIND_I2, t, NULL);
895 case MB_TERM_STIND_REF:
896 case MB_TERM_LDIND_REF:
897 t = ctree_dup_address (mp, s->left);
898 t = mono_ctree_new (mp, MB_TERM_LDIND_REF, t, NULL);
899 t->svt = VAL_POINTER;
901 case MB_TERM_STIND_I4:
902 case MB_TERM_LDIND_I4:
903 t = ctree_dup_address (mp, s->left);
904 t = mono_ctree_new (mp, MB_TERM_LDIND_I4, t, NULL);
907 case MB_TERM_LDIND_U4:
908 t = ctree_dup_address (mp, s->left);
909 t = mono_ctree_new (mp, MB_TERM_LDIND_U4, t, NULL);
912 case MB_TERM_STIND_I8:
913 case MB_TERM_LDIND_I8:
914 t = ctree_dup_address (mp, s->left);
915 t = mono_ctree_new (mp, MB_TERM_LDIND_I8, t, NULL);
918 case MB_TERM_STIND_R4:
919 case MB_TERM_LDIND_R4:
920 t = ctree_dup_address (mp, s->left);
921 t = mono_ctree_new (mp, MB_TERM_LDIND_R4, t, NULL);
924 case MB_TERM_STIND_R8:
925 case MB_TERM_LDIND_R8:
926 t = ctree_dup_address (mp, s->left);
927 t = mono_ctree_new (mp, MB_TERM_LDIND_R8, t, NULL);
931 g_warning ("unknown op \"%s\"", mono_burg_term_string [s->op]);
932 g_assert_not_reached ();
939 mono_store_tree (MonoFlowGraph *cfg, int slot, MBTree *s, MBTree **dup)
941 MonoMemPool *mp = cfg->mp;
946 case MB_TERM_STIND_I1:
947 case MB_TERM_LDIND_I1:
948 case MB_TERM_STIND_I2:
949 case MB_TERM_LDIND_I2:
950 case MB_TERM_STIND_I4:
951 case MB_TERM_LDIND_I4:
952 case MB_TERM_STIND_REF:
953 case MB_TERM_LDIND_REF:
954 case MB_TERM_STIND_I8:
955 case MB_TERM_LDIND_I8:
956 case MB_TERM_STIND_R4:
957 case MB_TERM_LDIND_R4:
958 case MB_TERM_STIND_R8:
959 case MB_TERM_LDIND_R8: {
961 vnum = mono_allocate_intvar (cfg, slot, s->svt);
963 if (s->left->op == MB_TERM_ADDR_L && s->left->data.i == vnum) {
965 *dup = ctree_create_dup (mp, s);
971 *dup = ctree_create_dup (mp, s);
976 g_assert (s->svt != VAL_UNKNOWN);
979 vnum = mono_allocate_intvar (cfg, slot, s->svt);
982 mono_get_val_sizes (s->svt, &size, &align);
983 vnum = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, s->svt);
986 t = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
989 t = mono_ctree_new (mp, map_store_svt_type (s->svt), t, s);
995 mono_store_tree (cfg, -1, t, dup);
1001 mono_cfg_new (MonoMethod *method, MonoMemPool *mp)
1006 g_assert (((MonoMethodNormal *)method)->header);
1008 cfg = mono_mempool_alloc0 (mp, sizeof (MonoFlowGraph));
1010 cfg->domain = mono_domain_get ();
1011 cfg->method = method;
1014 /* fixme: we should also consider loader optimisation attributes */
1015 cfg->share_code = mono_jit_share_code;
1017 cfg->varinfo = g_array_new (FALSE, TRUE, sizeof (MonoVarInfo));
1019 SET_VARINFO (vi, 0, 0, 0, 0);
1020 g_array_append_val (cfg->varinfo, vi); /* add invalid value at position 0 */
1022 cfg->intvars = mono_mempool_alloc0 (mp, sizeof (guint16) * VAL_DOUBLE *
1023 ((MonoMethodNormal *)method)->header->max_stack);
1028 mono_cfg_free (MonoFlowGraph *cfg)
1032 for (i = 0; i < cfg->block_count; i++) {
1033 if (!cfg->bblocks [i].reached)
1035 g_ptr_array_free (cfg->bblocks [i].forest, TRUE);
1039 g_free (cfg->bcinfo);
1042 g_free (cfg->bblocks);
1044 g_array_free (cfg->varinfo, TRUE);
1049 runtime_object_init (MonoObject *obj)
1051 MonoClass *klass = obj->vtable->klass;
1052 MonoMethod *method = NULL;
1053 void (*ctor) (gpointer this);
1056 for (i = 0; i < klass->method.count; ++i) {
1057 if (!strcmp (".ctor", klass->methods [i]->name) &&
1058 klass->methods [i]->signature->param_count == 0) {
1059 method = klass->methods [i];
1066 ctor = arch_compile_method (method);
1071 mono_find_final_block (MonoFlowGraph *cfg, guint32 ip, int type)
1073 MonoMethod *method = cfg->method;
1074 MonoBytecodeInfo *bcinfo = cfg->bcinfo;
1075 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
1076 MonoExceptionClause *clause;
1079 for (i = 0; i < header->num_clauses; ++i) {
1080 clause = &header->clauses [i];
1081 if (MONO_OFFSET_IN_HANDLER (clause, ip))
1084 if (MONO_OFFSET_IN_CLAUSE (clause, ip)) {
1085 if (clause->flags & type) {
1086 g_assert (bcinfo [clause->handler_offset].is_block_start);
1087 return &cfg->bblocks [bcinfo [clause->handler_offset].block_id];
1095 #define CREATE_BLOCK(t) {if (!bcinfo [t].is_block_start) {block_count++;bcinfo [t].is_block_start = 1; }}
1098 mono_analyze_flow (MonoFlowGraph *cfg)
1100 MonoMethod *method = cfg->method;
1101 register const unsigned char *ip, *end;
1102 MonoMethodHeader *header;
1103 MonoBytecodeInfo *bcinfo;
1104 MonoExceptionClause *clause;
1105 MonoBBlock *bblocks, *bb;
1106 const MonoOpcode *opcode;
1110 header = ((MonoMethodNormal *)method)->header;
1112 bcinfo = g_malloc0 (header->code_size * sizeof (MonoBytecodeInfo));
1113 bcinfo [0].is_block_start = 1;
1118 end = ip + header->code_size;
1120 mono_jit_stats.cil_code_size += header->code_size;
1122 /* fixme: add block boundaries for exceptions */
1123 for (i = 0; i < header->num_clauses; ++i) {
1124 clause = &header->clauses [i];
1125 CREATE_BLOCK (clause->try_offset);
1126 CREATE_BLOCK (clause->handler_offset);
1130 guint32 cli_addr = ip - header->code;
1132 //printf ("IL%04x OPCODE %s\n", cli_addr, opcode_names [*ip]);
1135 CREATE_BLOCK (cli_addr);
1146 opcode = &mono_opcodes [i];
1148 switch (opcode->flow_type) {
1149 case MONO_FLOW_RETURN:
1150 case MONO_FLOW_ERROR:
1153 case MONO_FLOW_BRANCH: /* we handle branch when checking the argument type */
1154 case MONO_FLOW_COND_BRANCH:
1155 case MONO_FLOW_CALL:
1156 case MONO_FLOW_NEXT:
1157 case MONO_FLOW_META:
1160 g_assert_not_reached ();
1163 switch (opcode->argument) {
1164 case MonoInlineNone:
1167 case MonoInlineString:
1168 mono_ldstr (mono_domain_get (), method->klass->image, mono_metadata_token_index (read32 (ip + 1)));
1170 case MonoInlineType:
1171 case MonoInlineField:
1172 case MonoInlineMethod:
1175 case MonoShortInlineR:
1182 case MonoShortInlineVar:
1183 case MonoShortInlineI:
1186 case MonoShortInlineBrTarget:
1188 i = (signed char)*ip;
1190 CREATE_BLOCK (cli_addr + 2 + i);
1193 case MonoInlineBrTarget:
1197 CREATE_BLOCK (cli_addr + 5 + i);
1200 case MonoInlineSwitch: {
1201 gint32 st, target, n;
1205 st = cli_addr + 5 + 4 * n;
1208 for (i = 0; i < n; i++) {
1209 target = read32 (ip) + st;
1211 CREATE_BLOCK (target);
1214 * Note: the code didn't set block_end in switch.
1223 g_assert_not_reached ();
1228 g_assert (block_count);
1230 bb = bblocks = g_malloc0 (sizeof (MonoBBlock) * block_count);
1233 bblocks [0].reached = 1;
1235 for (i = 0; i < header->code_size; i++) {
1236 if (bcinfo [i].is_block_start) {
1239 bb [-1].length = i - bb [-1].cli_addr;
1240 bcinfo [i].block_id = block_count;
1245 bb [-1].length = header->code_size - bb [-1].cli_addr;
1247 cfg->bcinfo = bcinfo;
1248 cfg->bblocks = bblocks;
1249 cfg->block_count = block_count;
1253 * ves_array_element_address:
1254 * @this: a pointer to the array object
1256 * Returns: the address of an array element.
1259 ves_array_element_address (MonoArray *this, ...)
1266 g_assert (this != NULL);
1270 class = this->obj.vtable->klass;
1272 ind = va_arg(ap, int) - this->bounds [0].lower_bound;
1273 for (i = 1; i < class->rank; i++) {
1274 ind = ind*this->bounds [i].length + va_arg(ap, int) -
1275 this->bounds [i].lower_bound;;
1278 esize = mono_array_element_size (class);
1279 ea = (gpointer*)((char*)this->vector + (ind * esize));
1280 //printf ("AADDRESS %p %p %d\n", this, ea, ind);
1288 mono_array_new_va (MonoMethod *cm, ...)
1290 MonoDomain *domain = mono_domain_get ();
1293 guint32 *lower_bounds;
1294 int pcount = cm->signature->param_count;
1295 int rank = cm->klass->rank;
1300 lengths = alloca (sizeof (guint32) * pcount);
1301 for (i = 0; i < pcount; ++i)
1302 lengths [i] = d = va_arg(ap, int);
1304 if (rank == pcount) {
1305 /* Only lengths provided. */
1306 lower_bounds = NULL;
1308 g_assert (pcount == (rank * 2));
1309 /* lower bounds are first. */
1310 lower_bounds = lengths;
1315 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
1318 #define ADD_TREE(t,a) do { t->cli_addr = a; g_ptr_array_add (forest, (t)); } while (0)
1319 #define PUSH_TREE(t,k) do { int tt = k; *sp = t; t->svt = tt; sp++; } while (0)
1321 #define LOCAL_POS(n) (1 + n)
1322 #define LOCAL_TYPE(n) ((header)->locals [(n)])
1324 #define ARG_POS(n) (firstarg + n)
1325 #define ARG_TYPE(n) ((n) ? (signature)->params [(n) - (signature)->hasthis] : \
1326 (signature)->hasthis ? &method->klass->this_arg: (signature)->params [(0)])
1329 create_outstack (MonoFlowGraph *cfg, MonoBBlock *bb, MBTree **stack, int depth)
1331 MonoMemPool *mp = cfg->mp;
1332 MBTree **c = stack, *t1, *t2;
1333 GPtrArray *forest = bb->forest;
1336 g_assert (bb->reached);
1342 g_assert (bb->outdepth == depth);
1346 bb->outdepth = depth;
1347 bb->outstack = mono_mempool_alloc (mp, depth * sizeof (MBTree *));
1349 for (i = 0; i < depth; i++) {
1350 if ((t1 = mono_store_tree (cfg, i, c [i], &t2)))
1352 bb->outstack [i] = t2;
1357 mark_reached (MonoFlowGraph *cfg, MonoBBlock *target, MBTree **stack, int depth)
1359 MonoMemPool *mp = cfg->mp;
1362 if (target->reached)
1365 target->reached = 1;
1372 if (target->instack) {
1373 g_assert (target->indepth == depth);
1377 target->indepth = depth;
1378 target->instack = mono_mempool_alloc (mp, depth * sizeof (MBTree *));
1380 for (i = 0; i < depth; i++) {
1381 target->instack [i] = ctree_create_dup (mp, stack [i]);
1387 #define MARK_REACHED(bb) do { if (!bb->reached) { bb->reached = 1; }} while (0)
1390 * mono_analyze_stack:
1391 * @cfg: control flow graph
1393 * This is the architecture independent part of JIT compilation.
1394 * It creates a forest of trees which can then be fed into the
1395 * architecture dependent code generation.
1397 * The algorithm is from Andi Krall, the same is used in CACAO
1400 mono_analyze_stack (MonoFlowGraph *cfg)
1402 MonoMethod *method = cfg->method;
1403 MonoMemPool *mp = cfg->mp;
1404 MonoBytecodeInfo *bcinfo = cfg->bcinfo;
1405 MonoMethodHeader *header;
1406 MonoMethodSignature *signature;
1409 MBTree **sp, **stack, **arg_sp, *t1, *t2, *t3;
1410 register const unsigned char *ip, *end;
1412 int i, j, depth, repeat_count;
1413 int varnum = 0, firstarg = 0, retvtarg = 0;
1414 gboolean repeat, superblock_end;
1415 MonoBBlock *bb, *tbb;
1417 header = ((MonoMethodNormal *)method)->header;
1418 signature = method->signature;
1419 image = method->klass->image;
1421 sp = stack = alloca (sizeof (MBTree *) * (header->max_stack + 1));
1423 if (header->num_locals) {
1426 for (i = 0; i < header->num_locals; ++i) {
1427 size = mono_type_size (header->locals [i], &align);
1428 varnum = arch_allocate_var (cfg, size, align, MONO_LOCALVAR, VAL_UNKNOWN);
1430 cfg->locals_start_index = varnum;
1434 if (ISSTRUCT (signature->ret)) {
1439 size = mono_type_size (signature->ret, &align);
1441 retvtarg = varnum = arch_allocate_var (cfg, size, align, MONO_LOCALVAR, VAL_UNKNOWN);
1443 //printf ("VALUETYPE METHOD %s.%s::%s %d\n", method->klass->name_space,
1444 //method->klass->name, method->name, size);
1447 cfg->args_start_index = firstarg = varnum + 1;
1449 if (signature->hasthis) {
1450 arch_allocate_var (cfg, sizeof (gpointer), sizeof (gpointer), MONO_ARGVAR, VAL_POINTER);
1453 if (signature->param_count) {
1456 for (i = 0; i < signature->param_count; ++i) {
1457 size = mono_type_stack_size (signature->params [i], &align);
1458 arch_allocate_var (cfg, size, align, MONO_ARGVAR, VAL_UNKNOWN);
1462 for (i = 0; i < header->num_clauses; ++i) {
1463 MonoExceptionClause *clause = &header->clauses [i];
1464 tbb = &cfg->bblocks [bcinfo [clause->handler_offset].block_id];
1465 if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) {
1466 tbb->instack = mono_mempool_alloc (mp, sizeof (MBTree *));
1468 tbb->instack [0] = t1 = mono_ctree_new_leaf (mp, MB_TERM_EXCEPTION);
1469 t1->data.i = mono_allocate_excvar (cfg);
1470 t1->svt = VAL_POINTER;
1472 } else if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
1473 mark_reached (cfg, tbb, NULL, 0);
1475 g_warning ("implement me");
1476 g_assert_not_reached ();
1484 superblock_end = TRUE;
1487 //printf ("START\n");
1488 for (i = 0; i < cfg->block_count; i++) {
1489 bb = &cfg->bblocks [i];
1491 //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);
1493 if (!bb->reached && !superblock_end) {
1494 MonoBBlock *sbb = &cfg->bblocks [i - 1];
1496 g_assert (sbb->outdepth == (sp - stack));
1498 mark_reached (cfg, bb, sbb->outstack, sbb->outdepth);
1503 if (!bb->finished) {
1507 for (j = 0; j < bb->indepth; j++) {
1508 sp [j] = bb->instack [j];
1514 ip = header->code + bb->cli_addr;
1515 end = ip + bb->length;
1517 bb->forest = forest = g_ptr_array_new ();
1519 superblock_end = FALSE;
1522 guint32 cli_addr = ip - header->code;
1524 //printf ("%d IL%04x OPCODE %s %d %d %d\n", i, cli_addr, opcode_names [*ip],
1525 //forest->len, superblock_end, sp - stack);
1532 t1 = mono_ctree_new (mp, MB_TERM_THROW, *sp, NULL);
1533 ADD_TREE (t1, cli_addr);
1534 superblock_end = TRUE;
1543 token = read32 (ip);
1546 c = mono_class_get (image, token);
1548 t1 = mono_ctree_new_leaf (mp, MB_TERM_NEWOBJ);
1550 t1->svt = VAL_POINTER;
1552 t1 = mono_store_tree (cfg, -1, t1, &t3);
1554 ADD_TREE (t1, cli_addr);
1556 t1 = ctree_create_dup (mp, t3);
1557 t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1558 t2->data.i = sizeof (MonoObject);
1559 t1 = mono_ctree_new (mp, MB_TERM_ADD, t1, t2);
1561 t1 = ctree_create_store (cfg, &c->byval_arg, t1, *sp, FALSE);
1562 ADD_TREE (t1, cli_addr);
1564 PUSH_TREE (t3, VAL_POINTER);
1573 token = read32 (ip);
1577 class = mono_class_get (image, token);
1578 t1 = mono_ctree_new (mp, MB_TERM_UNBOX, *sp, NULL);
1579 t1->data.klass = class;
1581 PUSH_TREE (t1, VAL_POINTER);
1588 t1 = mono_ctree_new (mp, MB_TERM_LDLEN, *sp, NULL);
1589 PUSH_TREE (t1, VAL_I32);
1598 token = read32 (ip);
1602 c = mono_class_get (image, token);
1603 g_assert (c->valuetype);
1605 t1 = ctree_create_load (cfg, &c->byval_arg, *sp, &svt, FALSE);
1606 PUSH_TREE (t1, svt);
1615 token = read32 (ip);
1619 c = mono_class_get (image, token);
1620 g_assert (c->valuetype);
1622 size = mono_class_value_size (c, NULL);
1624 t1 = mono_ctree_new (mp, MB_TERM_STIND_OBJ, sp [0], sp [1]);
1626 ADD_TREE (t1, cli_addr);
1634 index = mono_metadata_token_index (read32 (ip));
1637 if (cfg->share_code) {
1638 t1 = mono_ctree_new_leaf (mp, MB_TERM_LDSTR);
1641 o = (MonoObject *) mono_ldstr (cfg->domain, image, index);
1642 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1646 PUSH_TREE (t1, VAL_POINTER);
1652 MonoClassField *field;
1654 int load_addr = *ip == CEE_LDSFLDA;
1657 token = read32 (ip);
1660 /* need to handle fieldrefs */
1661 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
1662 field = mono_field_from_memberref (image, token, &klass);
1663 mono_class_init (klass);
1665 klass = mono_class_get (image,
1666 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
1667 mono_class_init (klass);
1668 field = mono_class_get_field (klass, token);
1673 if (cfg->share_code) {
1674 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1675 t1->data.i = field->offset;
1676 t1 = mono_ctree_new (mp, MB_TERM_LDSFLDA, t1, NULL);
1677 t1->data.klass = klass;
1679 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
1680 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
1681 t1->data.p = (char*)(vt->data) + field->offset;
1687 t1 = ctree_create_load (cfg, field->type, t1, &svt, FALSE);
1690 PUSH_TREE (t1, svt);
1696 MonoClassField *field;
1698 int load_addr = *ip == CEE_LDFLDA;
1701 token = read32 (ip);
1705 /* need to handle fieldrefs */
1706 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
1707 field = mono_field_from_memberref (image, token, &klass);
1708 mono_class_init (klass);
1710 klass = mono_class_get (image,
1711 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
1712 mono_class_init (klass);
1713 field = mono_class_get_field (klass, token);
1717 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1719 if (klass->valuetype)
1720 t1->data.i = field->offset - sizeof (MonoObject);
1722 t1->data.i = field->offset;
1724 t1 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], t1);
1727 t1 = ctree_create_load (cfg, field->type, t1, &svt, FALSE);
1731 PUSH_TREE (t1, svt);
1736 MonoClassField *field;
1740 token = read32 (ip);
1744 /* need to handle fieldrefs */
1745 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
1746 field = mono_field_from_memberref (image, token, &klass);
1747 mono_class_init (klass);
1749 klass = mono_class_get (image,
1750 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
1751 mono_class_init (klass);
1752 field = mono_class_get_field (klass, token);
1757 if (cfg->share_code) {
1758 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1759 t1->data.i = field->offset;
1760 t1 = mono_ctree_new (mp, MB_TERM_LDSFLDA, t1, NULL);
1761 t1->data.klass = klass;
1763 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
1764 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
1765 t1->data.p = (char*)(vt->data) + field->offset;
1767 t1 = ctree_create_store (cfg, field->type, t1, *sp, FALSE);
1769 ADD_TREE (t1, cli_addr);
1774 MonoClassField *field;
1778 token = read32 (ip);
1782 /* need to handle fieldrefs */
1783 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
1784 field = mono_field_from_memberref (image, token, &klass);
1785 mono_class_init (klass);
1787 klass = mono_class_get (image,
1788 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
1789 mono_class_init (klass);
1790 field = mono_class_get_field (klass, token);
1794 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1795 if (klass->valuetype)
1796 t1->data.i = field->offset - sizeof (MonoObject);
1798 t1->data.i = field->offset;
1800 //printf ("VALUETYPE %d %d %d\n", klass->valuetype, field->offset, t1->data.i);
1802 t1 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], t1);
1803 t1 = ctree_create_store (cfg, field->type, t1, sp [1], FALSE);
1805 ADD_TREE (t1, cli_addr);
1810 guint32 esize, token;
1813 token = read32 (ip);
1817 class = mono_class_get (image, token);
1819 mono_class_init (class);
1821 esize = mono_class_instance_size (class);
1822 if (class->valuetype)
1823 esize -= sizeof (MonoObject);
1825 t1 = mono_ctree_new (mp, MB_TERM_LDELEMA, sp [0], sp [1]);
1827 PUSH_TREE (t1, VAL_POINTER);
1836 t1 = mono_ctree_new_leaf (mp, MB_TERM_BREAK);
1837 ADD_TREE (t1, cli_addr);
1850 t1 = mono_ctree_new (mp, MB_TERM_SWITCH, *sp, NULL);
1851 jt = t1->data.p = mono_alloc_static (sizeof (gpointer) * (n + 2));
1852 st = cli_addr + 5 + 4 * n;
1854 // hack: we store n at position 0
1855 jt [0] = (MonoBBlock *)n;
1857 create_outstack (cfg, bb, stack, sp - stack);
1859 for (i = 1; i <= (n + 1); i++) {
1863 target = read32 (ip) + st;
1866 g_assert (target >= 0 && target <= header->code_size);
1867 g_assert (bcinfo [target].is_block_start);
1868 tbb = &cfg->bblocks [bcinfo [target].block_id];
1869 mark_reached (cfg, tbb, stack, sp - stack);
1873 ADD_TREE (t1, cli_addr);
1878 MonoClass *handle_class;
1881 handle = mono_ldtoken (image, read32 (ip), &handle_class);
1884 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1885 t1->data.p = handle;
1886 PUSH_TREE (t1, VAL_POINTER);
1896 token = read32 (ip);
1897 class = mono_class_get (image, token);
1900 t1 = mono_ctree_new (mp, MB_TERM_NEWARR, *sp, NULL);
1902 PUSH_TREE (t1, VAL_POINTER);
1911 token = read32 (ip);
1912 class = mono_class_get (image, token);
1916 t1 = mono_ctree_new (mp, MB_TERM_CPOBJ, sp [0], sp [1]);
1917 ADD_TREE (t1, cli_addr);
1922 MonoMethodSignature *csig;
1925 MBTree *this = NULL;
1927 int i, align, size, args_size = 0;
1931 token = read32 (ip);
1934 cm = mono_get_method (image, token, NULL);
1936 g_assert (!strcmp (cm->name, ".ctor"));
1938 ci = mono_mempool_alloc0 (mp, sizeof (MethodCallInfo));
1941 csig = cm->signature;
1942 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
1943 g_assert (csig->hasthis);
1945 arg_sp = sp -= csig->param_count;
1947 if (!cm->klass->inited)
1948 mono_class_init (cm->klass);
1950 if (cm->klass->parent == mono_defaults.array_class) {
1952 this = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1955 if (cm->klass->valuetype) {
1956 this = mono_ctree_new_leaf (mp, MB_TERM_NEWSTRUCT);
1957 this->data.i = mono_class_value_size (cm->klass, NULL);
1959 this = mono_ctree_new_leaf (mp, MB_TERM_NEWOBJ);
1960 this->data.klass = cm->klass;
1963 this->svt = VAL_POINTER;
1965 t1 = mono_store_tree (cfg, -1, this, &this);
1967 ADD_TREE (t1, cli_addr);
1970 args_size += sizeof (gpointer); /* this argument */
1972 for (i = csig->param_count - 1; i >= 0; i--) {
1973 MonoType *type = cm->signature->params [i];
1975 size = mono_type_stack_size (type, &align);
1976 t1 = mono_ctree_new (mp, map_arg_type (type), arg_sp [i], NULL);
1978 ADD_TREE (t1, cli_addr);
1982 ci->args_size = args_size;
1986 t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
1987 t2->data.p = mono_array_new_va;
1989 t1 = mono_ctree_new (mp, MB_TERM_CALL_I4, this, t2);
1991 t1->svt = VAL_POINTER;
1993 t1 = mono_store_tree (cfg, -1, t1, &t2);
1995 ADD_TREE (t1, cli_addr);
1996 PUSH_TREE (t2, t2->svt);
2000 t2 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
2001 t2->data.p = arch_create_jit_trampoline (cm);
2003 t1 = mono_ctree_new (mp, map_call_type (csig->ret, &svt), this, t2);
2007 ADD_TREE (t1, cli_addr);
2008 t1 = ctree_create_dup (mp, this);
2010 if (cm->klass->valuetype) {
2011 t2 = ctree_create_load (cfg, &cm->klass->byval_arg, t1, &svt, FALSE);
2012 PUSH_TREE (t2, svt);
2014 PUSH_TREE (t1, t1->svt);
2020 case CEE_CALLVIRT: {
2021 MonoMethodSignature *csig;
2024 MBTree *this = NULL;
2026 int i, align, size, args_size = 0;
2027 int virtual = *ip == CEE_CALLVIRT;
2028 gboolean array_set = FALSE;
2029 gboolean array_get = FALSE;
2030 int nargs, vtype_num = 0;
2033 token = read32 (ip);
2036 cm = mono_get_method (image, token, NULL);
2039 ci = mono_mempool_alloc0 (mp, sizeof (MethodCallInfo));
2042 if ((cm->flags & METHOD_ATTRIBUTE_FINAL) ||
2043 !(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
2046 csig = cm->signature;
2047 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
2048 g_assert (!virtual || csig->hasthis);
2050 /* fixme: we need to unbox the this pointer for value types ?*/
2051 g_assert (!virtual || !cm->klass->valuetype);
2053 nargs = csig->param_count;
2054 arg_sp = sp -= nargs;
2056 if (cm->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
2057 if (cm->klass->parent == mono_defaults.array_class) {
2058 if (!strcmp (cm->name, "Set")) {
2061 } else if (!strcmp (cm->name, "Get"))
2066 for (i = nargs - 1; i >= 0; i--) {
2067 MonoType *type = cm->signature->params [i];
2068 t1 = mono_ctree_new (mp, map_arg_type (type), arg_sp [i], NULL);
2069 size = mono_type_stack_size (type, &align);
2071 ADD_TREE (t1, cli_addr);
2073 // fixme: align value type arguments to 8 byte boundary on the stack
2076 if (csig->hasthis) {
2078 args_size += sizeof (gpointer);
2080 this = mono_ctree_new_leaf (mp, MB_TERM_NOP);
2082 if (ISSTRUCT (csig->ret)) {
2084 size = mono_type_size (csig->ret, &align);
2085 vtype_num = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, VAL_UNKNOWN);
2088 ci->args_size = args_size;
2089 ci->vtype_num = vtype_num;
2092 int size, align, vnum;
2094 t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2095 t2->data.p = ves_array_element_address;
2097 t1 = mono_ctree_new (mp, MB_TERM_CALL_I4, this, t2);
2100 t1 = mono_ctree_new (mp, map_ldind_type (csig->ret, &svt), t1, NULL);
2103 mono_get_val_sizes (t1->svt, &size, &align);
2104 vnum = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, svt);
2106 t2 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2108 t1 = mono_ctree_new (mp, map_store_svt_type (svt), t2, t1);
2111 ADD_TREE (t1, cli_addr);
2112 t1 = ctree_create_dup (mp, t1);
2113 PUSH_TREE (t1, t1->svt);
2115 } else if (array_set) {
2117 t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2118 t2->data.p = ves_array_element_address;
2120 t1 = mono_ctree_new (mp, MB_TERM_CALL_I4, this, t2);
2123 t1 = ctree_create_store (cfg, csig->params [nargs], t1, arg_sp [nargs], FALSE);
2124 ADD_TREE (t1, cli_addr);
2129 mono_class_init (cm->klass);
2131 if (cm->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
2132 t2 = mono_ctree_new_leaf (mp, MB_TERM_INTF_ADDR);
2134 t2 = mono_ctree_new_leaf (mp, MB_TERM_VFUNC_ADDR);
2140 t2 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
2141 t2->data.p = arch_create_jit_trampoline (cm);
2144 t1 = mono_ctree_new (mp, map_call_type (csig->ret, &svt), this, t2);
2148 if (csig->ret->type != MONO_TYPE_VOID) {
2151 ADD_TREE (t1, cli_addr);
2152 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2153 t1->data.i = vtype_num;
2154 PUSH_TREE (t1, VAL_POINTER);
2156 t1 = mono_store_tree (cfg, -1, t1, &t2);
2158 ADD_TREE (t1, cli_addr);
2159 PUSH_TREE (t2, t2->svt);
2162 ADD_TREE (t1, cli_addr);
2172 token = read32 (ip);
2175 c = mono_class_get (image, token);
2177 t1 = mono_ctree_new (mp, MB_TERM_ISINST, *sp, NULL);
2180 PUSH_TREE (t1, VAL_POINTER);
2185 case CEE_CASTCLASS: {
2189 token = read32 (ip);
2192 c = mono_class_get (image, token);
2194 t1 = mono_ctree_new (mp, MB_TERM_CASTCLASS, *sp, NULL);
2197 PUSH_TREE (t1, VAL_POINTER);
2202 case CEE_LDC_I4_S: {
2204 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2205 t1->data.i = *(gint8 *)ip;
2207 PUSH_TREE (t1, VAL_I32);
2212 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2213 t1->data.i = read32 (ip);
2215 PUSH_TREE (t1, VAL_I32);
2227 case CEE_LDC_I4_8: {
2228 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2229 t1->data.i = (*ip) - CEE_LDC_I4_0;
2231 PUSH_TREE (t1, VAL_I32);
2235 //fixme: don't know if this is portable ?
2237 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2239 PUSH_TREE (t1, VAL_POINTER);
2244 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I8);
2245 t1->data.l = read64 (ip);
2247 PUSH_TREE (t1, VAL_I64);
2251 float *f = mono_alloc_static (sizeof (float));
2253 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_R4);
2257 PUSH_TREE (t1, VAL_DOUBLE);
2261 double *d = mono_alloc_static (sizeof (double));
2263 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_R8);
2267 PUSH_TREE (t1, VAL_DOUBLE);
2274 int n = (*ip) - CEE_LDLOC_0;
2277 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2278 t1->data.i = LOCAL_POS (n);
2279 if (!ISSTRUCT (LOCAL_TYPE (n)))
2280 t1 = ctree_create_load (cfg, LOCAL_TYPE (n), t1, &svt, FALSE);
2282 PUSH_TREE (t1, svt);
2288 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2289 t1->data.i = LOCAL_POS (*ip);
2290 if (!ISSTRUCT (LOCAL_TYPE (*ip)))
2291 t1 = ctree_create_load (cfg, LOCAL_TYPE (*ip), t1, &svt, FALSE);
2294 PUSH_TREE (t1, svt);
2297 case CEE_LDLOCA_S: {
2300 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2301 t1->data.i = LOCAL_POS (*ip);
2303 PUSH_TREE (t1, VAL_POINTER);
2310 int n = (*ip) - CEE_STLOC_0;
2314 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2315 t1->data.i = LOCAL_POS (n);
2316 t1 = ctree_create_store (cfg, LOCAL_TYPE (n), t1, *sp, FALSE);
2318 ADD_TREE (t1, cli_addr);
2325 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2326 t1->data.i = LOCAL_POS (*ip);
2327 t1 = ctree_create_store (cfg, LOCAL_TYPE (*ip), t1, *sp, FALSE);
2330 ADD_TREE (t1, cli_addr);
2337 t1 = mono_ctree_new (mp, MB_TERM_SHR, sp [0], sp [1]);
2338 PUSH_TREE (t1, sp [0]->svt);
2344 t1 = mono_ctree_new (mp, MB_TERM_SHR_UN, sp [0], sp [1]);
2345 PUSH_TREE (t1, sp [0]->svt);
2351 t1 = mono_ctree_new (mp, MB_TERM_SHL, sp [0], sp [1]);
2352 PUSH_TREE (t1, sp [0]->svt);
2357 MAKE_BI_ALU (ADD_OVF)
2358 MAKE_BI_ALU (ADD_OVF_UN)
2360 MAKE_BI_ALU (SUB_OVF)
2361 MAKE_BI_ALU (SUB_OVF_UN)
2365 MAKE_SPILLED_BI_ALU (MUL)
2366 MAKE_SPILLED_BI_ALU (MUL_OVF)
2367 MAKE_SPILLED_BI_ALU (MUL_OVF_UN)
2368 MAKE_SPILLED_BI_ALU (DIV)
2369 MAKE_SPILLED_BI_ALU (DIV_UN)
2370 MAKE_SPILLED_BI_ALU (REM)
2371 MAKE_SPILLED_BI_ALU (REM_UN)
2373 MAKE_LDIND (LDIND_I1, MB_TERM_LDIND_I1, VAL_I32)
2374 MAKE_LDIND (LDIND_U1, MB_TERM_LDIND_U1, VAL_I32)
2375 MAKE_LDIND (LDIND_I2, MB_TERM_LDIND_I2, VAL_I32)
2376 MAKE_LDIND (LDIND_U2, MB_TERM_LDIND_U2, VAL_I32)
2377 MAKE_LDIND (LDIND_I, MB_TERM_LDIND_I4, VAL_I32)
2378 MAKE_LDIND (LDIND_I4, MB_TERM_LDIND_I4, VAL_I32)
2379 MAKE_LDIND (LDIND_REF, MB_TERM_LDIND_REF, VAL_POINTER)
2380 MAKE_LDIND (LDIND_U4, MB_TERM_LDIND_U4, VAL_I32)
2381 MAKE_LDIND (LDIND_I8, MB_TERM_LDIND_I8, VAL_I64)
2382 MAKE_LDIND (LDIND_R4, MB_TERM_LDIND_R4, VAL_DOUBLE)
2383 MAKE_LDIND (LDIND_R8, MB_TERM_LDIND_R8, VAL_DOUBLE)
2385 MAKE_STIND (STIND_I1, MB_TERM_STIND_I1)
2386 MAKE_STIND (STIND_I2, MB_TERM_STIND_I2)
2387 MAKE_STIND (STIND_I, MB_TERM_STIND_I4)
2388 MAKE_STIND (STIND_I4, MB_TERM_STIND_I4)
2389 MAKE_STIND (STIND_I8, MB_TERM_STIND_I8)
2390 MAKE_STIND (STIND_R4, MB_TERM_STIND_R4)
2391 MAKE_STIND (STIND_R8, MB_TERM_STIND_R8)
2392 MAKE_STIND (STIND_REF, MB_TERM_STIND_REF)
2394 MAKE_LDELEM (LDELEM_I1, MB_TERM_LDIND_I1, VAL_I32, 1)
2395 MAKE_LDELEM (LDELEM_U1, MB_TERM_LDIND_U1, VAL_I32, 1)
2396 MAKE_LDELEM (LDELEM_I2, MB_TERM_LDIND_I2, VAL_I32, 2)
2397 MAKE_LDELEM (LDELEM_U2, MB_TERM_LDIND_U2, VAL_I32, 2)
2398 MAKE_LDELEM (LDELEM_I, MB_TERM_LDIND_I4, VAL_I32, 4)
2399 MAKE_LDELEM (LDELEM_I4, MB_TERM_LDIND_I4, VAL_I32, 4)
2400 MAKE_LDELEM (LDELEM_REF, MB_TERM_LDIND_REF, VAL_POINTER, sizeof (gpointer))
2401 MAKE_LDELEM (LDELEM_U4, MB_TERM_LDIND_U4, VAL_I32, 4)
2402 MAKE_LDELEM (LDELEM_I8, MB_TERM_LDIND_I8, VAL_I64, 8)
2403 MAKE_LDELEM (LDELEM_R4, MB_TERM_LDIND_R4, VAL_DOUBLE, 4)
2404 MAKE_LDELEM (LDELEM_R8, MB_TERM_LDIND_R8, VAL_DOUBLE, 8)
2406 MAKE_STELEM (STELEM_I1, MB_TERM_STIND_I1, 1)
2407 MAKE_STELEM (STELEM_I2, MB_TERM_STIND_I2, 2)
2408 MAKE_STELEM (STELEM_I4, MB_TERM_STIND_I4, 4)
2409 MAKE_STELEM (STELEM_I, MB_TERM_STIND_I4, 4)
2410 MAKE_STELEM (STELEM_REF, MB_TERM_STIND_REF, sizeof (gpointer))
2411 MAKE_STELEM (STELEM_I8, MB_TERM_STIND_I8, 8)
2412 MAKE_STELEM (STELEM_R4, MB_TERM_STIND_R4, 4)
2413 MAKE_STELEM (STELEM_R8, MB_TERM_STIND_R8, 8)
2418 t1 = mono_ctree_new (mp, MB_TERM_NEG, sp [0], NULL);
2419 PUSH_TREE (t1, sp [0]->svt);
2425 t1 = mono_ctree_new (mp, MB_TERM_NOT, sp [0], NULL);
2426 PUSH_TREE (t1, sp [0]->svt);
2432 int br_s = (*ip == CEE_BR_S);
2436 target = cli_addr + 2 + (signed char) *ip;
2438 target = cli_addr + 5 + (gint32) read32(ip);
2440 g_assert (target >= 0 && target <= header->code_size);
2441 g_assert (bcinfo [target].is_block_start);
2442 tbb = &cfg->bblocks [bcinfo [target].block_id];
2443 create_outstack (cfg, bb, stack, sp - stack);
2444 mark_reached (cfg, tbb, bb->outstack, bb->outdepth);
2446 t1 = mono_ctree_new_leaf (mp, MB_TERM_BR);
2448 ADD_TREE (t1, cli_addr);
2455 superblock_end = TRUE;
2462 int leave_s = (*ip == CEE_LEAVE_S);
2466 target = cli_addr + 2 + (signed char) *ip;
2468 target = cli_addr + 5 + (gint32) read32(ip);
2470 g_assert (target >= 0 && target <= header->code_size);
2471 g_assert (bcinfo [target].is_block_start);
2472 tbb = &cfg->bblocks [bcinfo [target].block_id];
2474 /* empty the stack */
2477 mark_reached (cfg, tbb, NULL, 0);
2479 /* fixme: fault handler */
2481 if ((hb = mono_find_final_block (cfg, cli_addr, MONO_EXCEPTION_CLAUSE_FINALLY))) {
2482 mark_reached (cfg, hb, NULL, 0);
2483 t1 = mono_ctree_new_leaf (mp, MB_TERM_HANDLER);
2485 ADD_TREE (t1, cli_addr);
2488 t1 = mono_ctree_new_leaf (mp, MB_TERM_BR);
2490 ADD_TREE (t1, cli_addr);
2497 superblock_end = TRUE;
2514 case CEE_BRTRUE_S: {
2516 int near_jump = *ip == CEE_BRTRUE_S;
2520 t1 = mono_ctree_new (mp, MB_TERM_BRTRUE, sp [0], NULL);
2523 target = cli_addr + 2 + (signed char) *ip;
2525 target = cli_addr + 5 + (gint32) read32 (ip);
2527 g_assert (target >= 0 && target <= header->code_size);
2528 g_assert (bcinfo [target].is_block_start);
2529 tbb = &cfg->bblocks [bcinfo [target].block_id];
2530 create_outstack (cfg, bb, stack, sp - stack);
2531 mark_reached (cfg, tbb, bb->outstack, bb->outdepth);
2534 ip += near_jump ? 1: 4;
2535 ADD_TREE (t1, cli_addr);
2539 case CEE_BRFALSE_S: {
2541 int near_jump = *ip == CEE_BRFALSE_S;
2545 t1 = mono_ctree_new (mp, MB_TERM_BRFALSE, sp [0], NULL);
2548 target = cli_addr + 2 + (signed char) *ip;
2550 target = cli_addr + 5 + (gint32) read32 (ip);
2552 g_assert (target >= 0 && target <= header->code_size);
2553 g_assert (bcinfo [target].is_block_start);
2554 tbb = &cfg->bblocks [bcinfo [target].block_id];
2555 create_outstack (cfg, bb, stack, sp - stack);
2556 mark_reached (cfg, tbb, bb->outstack, bb->outdepth);
2559 ip += near_jump ? 1: 4;
2560 ADD_TREE (t1, cli_addr);
2564 MonoType *ret = signature->ret;
2568 if (ret->type != MONO_TYPE_VOID) {
2570 if (ISSTRUCT (ret)) {
2572 t1 = mono_ctree_new (mp, MB_TERM_RET_OBJ, *sp, NULL);
2573 t1->data.i = mono_class_value_size (ret->data.klass, &align);
2575 t1 = mono_ctree_new (mp, MB_TERM_RET, *sp, NULL);
2578 t1 = mono_ctree_new_leaf (mp, MB_TERM_RET_VOID);
2581 t1->last_instr = (ip == (header->code + header->code_size));
2583 ADD_TREE (t1, cli_addr);
2586 g_warning ("more values on stack at IL_%04x: %d", ip - header->code, sp - stack);
2587 mono_print_ctree (sp [-1]);
2590 superblock_end = TRUE;
2593 case CEE_ENDFINALLY: {
2596 t1 = mono_ctree_new_leaf (mp, MB_TERM_ENDFINALLY);
2597 ADD_TREE (t1, cli_addr);
2598 t1->last_instr = FALSE;
2600 g_assert (sp == stack);
2601 superblock_end = TRUE;
2608 int n = (*ip) - CEE_LDARG_0;
2611 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2612 t1->data.i = ARG_POS (n);
2613 if (!ISSTRUCT (ARG_TYPE (n)))
2614 t1 = ctree_create_load (cfg, ARG_TYPE (n), t1, &svt, TRUE);
2616 PUSH_TREE (t1, svt);
2622 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2623 t1->data.i = ARG_POS (*ip);
2624 if (!ISSTRUCT (ARG_TYPE (*ip)))
2625 t1 = ctree_create_load (cfg, ARG_TYPE (*ip), t1, &svt, TRUE);
2626 PUSH_TREE (t1, svt);
2630 case CEE_LDARGA_S: {
2632 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2633 t1->data.i = ARG_POS (*ip);
2634 PUSH_TREE (t1, VAL_POINTER);
2642 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2643 t1->data.i = ARG_POS (*ip);
2644 t1 = ctree_create_store (cfg, ARG_TYPE (*ip), t1, *sp, TRUE);
2646 ADD_TREE (t1, cli_addr);
2655 vnum = mono_allocate_intvar (cfg, sp - stack, sp [0]->svt);
2656 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2659 t2 = mono_ctree_new (mp, map_store_svt_type (sp [0]->svt), t1, sp [0]);
2660 t2->svt = sp [0]->svt;
2661 ADD_TREE (t2, cli_addr);
2663 t1 = ctree_create_dup (mp, t2);
2664 PUSH_TREE (t1, t1->svt);
2665 t1 = ctree_create_dup (mp, t1);
2666 PUSH_TREE (t1, t1->svt);
2674 t1 = mono_ctree_new (mp, MB_TERM_POP, *sp, NULL);
2675 ADD_TREE (t1, cli_addr);
2683 t1 = mono_ctree_new (mp, MB_TERM_CONV_I1, *sp, NULL);
2684 PUSH_TREE (t1, VAL_I32);
2691 t1 = mono_ctree_new (mp, MB_TERM_CONV_I2, *sp, NULL);
2692 PUSH_TREE (t1, VAL_I32);
2701 t1 = mono_ctree_new (mp, MB_TERM_CONV_I4, *sp, NULL);
2702 PUSH_TREE (t1, VAL_I32);
2708 t1 = mono_ctree_new (mp, MB_TERM_CONV_I8, *sp, NULL);
2709 PUSH_TREE (t1, VAL_I64);
2715 t1 = mono_ctree_new (mp, MB_TERM_CONV_I8, *sp, NULL);
2716 PUSH_TREE (t1, VAL_I64);
2722 t1 = mono_ctree_new (mp, MB_TERM_CONV_R8, *sp, NULL);
2723 PUSH_TREE (t1, VAL_DOUBLE);
2729 t1 = mono_ctree_new (mp, MB_TERM_CONV_R4, *sp, NULL);
2730 PUSH_TREE (t1, VAL_DOUBLE);
2733 case CEE_CONV_R_UN: {
2736 t1 = mono_ctree_new (mp, MB_TERM_CONV_R_UN, *sp, NULL);
2737 PUSH_TREE (t1, VAL_DOUBLE);
2740 case CEE_CONV_OVF_I:
2741 case CEE_CONV_OVF_I4: {
2744 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I4, *sp, NULL);
2745 PUSH_TREE (t1, VAL_I32);
2748 case CEE_CONV_OVF_I_UN:
2749 case CEE_CONV_OVF_I4_UN: {
2752 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I4_UN, *sp, NULL);
2753 PUSH_TREE (t1, VAL_I32);
2756 case CEE_CONV_OVF_U:
2757 case CEE_CONV_OVF_U4: {
2760 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U4, *sp, NULL);
2761 PUSH_TREE (t1, VAL_I32);
2764 case CEE_CONV_OVF_I1: {
2767 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I1, *sp, NULL);
2768 PUSH_TREE (t1, VAL_I32);
2771 case CEE_CONV_OVF_I1_UN: {
2774 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I1_UN, *sp, NULL);
2775 PUSH_TREE (t1, VAL_I32);
2778 case CEE_CONV_OVF_U1_UN: {
2781 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U1_UN, *sp, NULL);
2782 PUSH_TREE (t1, VAL_I32);
2786 case CEE_CONV_OVF_U1: {
2789 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U1, *sp, NULL);
2790 PUSH_TREE (t1, VAL_I32);
2793 case CEE_CONV_OVF_I2: {
2796 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I2, *sp, NULL);
2797 PUSH_TREE (t1, VAL_I32);
2800 case CEE_CONV_OVF_U2_UN: {
2803 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U2_UN, *sp, NULL);
2804 PUSH_TREE (t1, VAL_I32);
2807 case CEE_CONV_OVF_U2: {
2810 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U2, *sp, NULL);
2811 PUSH_TREE (t1, VAL_I32);
2814 case CEE_CONV_OVF_I2_UN: {
2817 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I2_UN, *sp, NULL);
2818 PUSH_TREE (t1, VAL_I32);
2821 case CEE_CONV_OVF_U8: {
2824 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U8, *sp, NULL);
2825 PUSH_TREE (t1, VAL_I32);
2828 case CEE_CONV_OVF_U_UN:
2829 case CEE_CONV_OVF_U4_UN: {
2830 // fixme: raise exceptions ?
2833 t1 = mono_ctree_new (mp, MB_TERM_CONV_I4, *sp, NULL);
2834 PUSH_TREE (t1, VAL_I32);
2837 case CEE_CONV_OVF_I8_UN: {
2840 t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I8_UN, *sp, NULL);
2841 PUSH_TREE (t1, VAL_I64);
2853 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2854 t1->data.i = LOCAL_POS (n);
2855 if (!ISSTRUCT (LOCAL_TYPE (n)))
2856 t1 = ctree_create_load (cfg, LOCAL_TYPE (n), t1, &svt, FALSE);
2859 PUSH_TREE (t1, svt);
2865 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2866 t1->data.i = LOCAL_POS (read16 (ip));
2868 PUSH_TREE (t1, VAL_POINTER);
2875 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2876 t1->data.i = LOCAL_POS (read16 (ip));
2877 t1 = ctree_create_store (cfg, LOCAL_TYPE (read16 (ip)), t1, *sp, FALSE);
2880 ADD_TREE (t1, cli_addr);
2892 t1 = mono_ctree_new_leaf (mp, MB_TERM_RETHROW);
2893 t1->data.i = mono_allocate_excvar (cfg);
2894 ADD_TREE (t1, cli_addr);
2901 token = read32 (ip);
2904 cm = mono_get_method (image, token, NULL);
2907 t1 = mono_ctree_new_leaf (mp, MB_TERM_LDFTN);
2909 PUSH_TREE (t1, VAL_POINTER);
2912 case CEE_LDVIRTFTN: {
2916 token = read32 (ip);
2920 cm = mono_get_method (image, token, NULL);
2923 if (cm->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
2924 t2 = mono_ctree_new_leaf (mp, MB_TERM_INTF_ADDR);
2926 t2 = mono_ctree_new_leaf (mp, MB_TERM_VFUNC_ADDR);
2930 t1 = mono_ctree_new (mp, MB_TERM_LDVIRTFTN, *sp, t2);
2932 PUSH_TREE (t1, VAL_POINTER);
2941 token = read32 (ip);
2942 class = mono_class_get (image, token);
2946 t1 = mono_ctree_new (mp, MB_TERM_INITOBJ, *sp, NULL);
2947 t1->data.i = mono_class_value_size (class, NULL);
2948 ADD_TREE (t1, cli_addr);
2958 t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
2959 t1->data.i = ARG_POS (n);
2960 if (!ISSTRUCT (ARG_TYPE (n)))
2961 t1 = ctree_create_load (cfg, ARG_TYPE (n), t1, &svt, TRUE);
2962 PUSH_TREE (t1, svt);
2970 token = read32 (ip);
2972 type = mono_type_create_from_typespec (image, token);
2973 t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
2974 t1->data.i = mono_type_size (type, &align);
2975 mono_metadata_free_type (type);
2976 PUSH_TREE (t1, VAL_I32);
2979 case CEE_UNALIGNED_: {
2981 // fixme: implement me
2984 case CEE_VOLATILE_: {
2986 // fixme: implement me
2990 g_error ("Unimplemented opcode at IL_%04x "
2991 "0xFE %02x", ip - header->code, *ip);
2996 g_warning ("unknown instruction `%s' at IL_%04X",
2997 opcode_names [*ip], ip - header->code);
2998 if (mono_debug_handle) {
3002 mono_print_forest (forest);
3003 g_assert_not_reached ();
3007 if ((depth = sp - stack)) {
3008 //printf ("DEPTH %d %d\n", depth, sp [0]->op);
3009 //mono_print_forest (forest);
3010 create_outstack (cfg, bb, stack, sp - stack);
3014 superblock_end = TRUE;
3017 superblock_end = TRUE;
3018 //printf ("unreached block %d\n", i);
3020 if (repeat_count >= 10) {
3021 /*mono_print_forest (forest);
3022 g_warning ("repeat count exceeded at ip: 0x%04x in %s\n", bb->cli_addr, cfg->method->name);*/
3026 //printf ("BBE %d %d %d %d\n", i, bb->reached, bb->finished, superblock_end);
3030 //printf ("REPEAT %d\n", repeat);
3031 mono_jit_stats.analyze_stack_repeat++;
3036 //printf ("FINISHED\n");
3039 /* this function is never called */
3041 ves_array_set (MonoArray *this, ...)
3043 g_assert_not_reached ();
3046 /* this function is never called */
3048 ves_array_get (MonoArray *this, ...)
3050 g_assert_not_reached ();
3054 * mono_jit_assembly:
3055 * @assembly: reference to an assembly
3057 * JIT compilation of all methods in the assembly. Prints debugging
3058 * information on stdout.
3061 mono_jit_assembly (MonoAssembly *assembly)
3063 MonoImage *image = assembly->image;
3065 MonoTableInfo *t = &image->tables [MONO_TABLE_METHOD];
3068 for (i = 0; i < t->rows; i++) {
3070 method = mono_get_method (image,
3071 (MONO_TABLE_METHOD << 24) | (i + 1),
3074 printf ("\nMethod: %s\n\n", method->name);
3076 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
3077 printf ("ABSTARCT\n");
3079 arch_compile_method (method);
3086 jit_exec_main (MonoMethod *method, MonoArray *args)
3088 gint32 (*mfunc) (MonoArray*);
3091 mfunc = arch_compile_method (method);
3095 if (method->signature->ret->type == MONO_TYPE_VOID)
3103 * @assembly: reference to an assembly
3104 * @argc: argument count
3105 * @argv: argument vector
3107 * Start execution of a program.
3110 mono_jit_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
3112 MonoArray *args = NULL;
3113 MonoImage *image = assembly->image;
3114 MonoCLIImageInfo *iinfo;
3117 iinfo = image->image_info;
3118 method = mono_get_method (image, iinfo->cli_cli_header.ch_entry_point, NULL);
3120 if (method->signature->param_count) {
3122 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3123 for (i = 0; i < argc; ++i) {
3124 MonoString *arg = mono_string_new (domain, argv [i]);
3125 mono_array_set (args, gpointer, i, arg);
3129 return mono_runtime_exec_main (method, args);
3136 "%s %s, the Mono ECMA CLI JIT Compiler, (C) 2001 Ximian, Inc.\n\n"
3137 "Usage is: %s [options] executable args...\n", name, VERSION, name);
3139 "Valid Options are:\n"
3140 "-d debug the jit, show disassembler output.\n"
3141 "--dump-asm dumps the assembly code generated\n"
3142 "--dump-forest dumps the reconstructed forest\n"
3143 "--trace-calls printf function call trace\n"
3144 "--share-code force jit to produce shared code\n"
3145 "--print-vtable print the VTable of all used classes\n"
3146 "--workers n maximum number of worker threads\n"
3147 "--stabs write stabs debug information\n"
3148 "--dwarf write dwarf2 debug information\n"
3149 "--dwarf-plus write extended dwarf2 debug information\n"
3150 "--stats print statistics about the jit operations\n"
3151 "--compile cname compile methods in given class (namespace.name[:methodname])\n"
3152 "--ncompile num compile methods num times (default: 1000)\n"
3153 "--debug name insert a breakpoint at the start of method name\n"
3154 "--help print this help message\n");
3159 sigfpe_signal_handler (int _dummy)
3162 void **_p = (void **)&_dummy;
3163 struct sigcontext *ctx = (struct sigcontext *)++_p;
3165 exc = mono_get_exception_divide_by_zero ();
3167 arch_handle_exception (ctx, exc);
3169 g_error ("we should never reach this code");
3173 sigill_signal_handler (int _dummy)
3176 void **_p = (void **)&_dummy;
3177 struct sigcontext *ctx = (struct sigcontext *)++_p;
3179 exc = mono_get_exception_execution_engine ("SIGILL");
3181 arch_handle_exception (ctx, exc);
3183 g_error ("we should never reach this code");
3187 sigsegv_signal_handler (int _dummy)
3190 void **_p = (void **)&_dummy;
3191 struct sigcontext *ctx = (struct sigcontext *)++_p;
3193 exc = mono_get_exception_null_reference ();
3195 arch_handle_exception (ctx, exc);
3197 g_error ("we should never reach this code");
3202 * @obj: exception object
3204 * abort the program, print exception information and stack trace
3207 mono_jit_abort (MonoObject *obj)
3215 if (mono_object_isinst (obj, mono_defaults.exception_class)) {
3216 if ((str = ((MonoException *)obj)->message))
3217 message = mono_string_to_utf8 (str);
3218 if ((str = ((MonoException *)obj)->stack_trace))
3219 trace = mono_string_to_utf8 (str);
3222 g_warning ("unhandled exception %s.%s: \"%s\"", obj->vtable->klass->name_space,
3223 obj->vtable->klass->name, message);
3235 my_GC_free (void *p)
3241 my_GC_calloc (gsize n_blocks, gsize n_block_bytes)
3243 return GC_malloc (n_block_bytes * n_blocks);
3248 main (int argc, char *argv [])
3251 struct sigaction sa;
3252 MonoAssembly *assembly;
3254 int compile_times = 1000;
3255 char *compile_class = NULL;
3257 gboolean testjit = FALSE;
3258 int stack, verbose = FALSE;
3259 CRITICAL_SECTION ms;
3261 mono_end_of_stack = &stack; /* a pointer to a local variable is always < BP */
3269 static GMemVTable boehm_table = {
3274 GC_malloc, /* try variants */
3277 g_mem_set_vtable (&boehm_table);
3282 for (i = 1; i < argc && argv [i][0] == '-'; i++){
3283 if (strcmp (argv [i], "--help") == 0) {
3285 } else if (strcmp (argv [i], "-d") == 0) {
3287 mono_jit_dump_asm = TRUE;
3288 mono_jit_dump_forest = TRUE;
3289 } else if (strcmp (argv [i], "--dump-asm") == 0)
3290 mono_jit_dump_asm = TRUE;
3291 else if (strcmp (argv [i], "--dump-forest") == 0)
3292 mono_jit_dump_forest = TRUE;
3293 else if (strcmp (argv [i], "--trace-calls") == 0)
3294 mono_jit_trace_calls = TRUE;
3295 else if (strcmp (argv [i], "--share-code") == 0)
3296 mono_jit_share_code = TRUE;
3297 else if (strcmp (argv [i], "--print-vtable") == 0)
3298 mono_print_vtable = TRUE;
3299 else if (strcmp (argv [i], "--debug") == 0) {
3300 MonoMethodDesc *desc = mono_method_desc_new (argv [++i], FALSE);
3302 g_error ("Invalid method name '%s'", argv [i]);
3303 mono_debug_methods = g_list_append (mono_debug_methods, desc);
3304 } else if (strcmp (argv [i], "--count") == 0) {
3305 compile_times = atoi (argv [++i]);
3306 } else if (strcmp (argv [i], "--workers") == 0) {
3307 mono_worker_threads = atoi (argv [++i]);
3308 if (mono_worker_threads < 1)
3309 mono_worker_threads = 1;
3310 } else if (strcmp (argv [i], "--compile") == 0) {
3311 compile_class = argv [++i];
3312 } else if (strcmp (argv [i], "--ncompile") == 0) {
3313 compile_times = atoi (argv [++i]);
3314 } else if (strcmp (argv [i], "--stats") == 0) {
3315 memset (&mono_jit_stats, 0, sizeof (MonoJitStats));
3316 mono_jit_stats.enabled = TRUE;
3317 } else if (strcmp (argv [i], "--stabs") == 0) {
3318 if (mono_debug_handle)
3319 g_error ("You can use either --stabs or --dwarf, but not both.");
3320 mono_debug_handle = mono_debug_open_file ("", MONO_DEBUG_FORMAT_STABS);
3321 } else if (strcmp (argv [i], "--dwarf") == 0) {
3322 if (mono_debug_handle)
3323 g_error ("You can use either --stabs or --dwarf, but not both.");
3324 mono_debug_handle = mono_debug_open_file ("", MONO_DEBUG_FORMAT_DWARF2);
3325 } else if (strcmp (argv [i], "--dwarf-plus") == 0) {
3326 if (mono_debug_handle)
3327 g_error ("You can use either --stabs or --dwarf, but not both.");
3328 mono_debug_handle = mono_debug_open_file ("", MONO_DEBUG_FORMAT_DWARF2_PLUS);
3329 } else if (strcmp (argv [i], "--verbose") == 0) {
3342 sa.sa_handler = sigfpe_signal_handler;
3343 sigemptyset (&sa.sa_mask);
3345 g_assert (syscall (SYS_sigaction, SIGFPE, &sa, NULL) != -1);
3348 sa.sa_handler = sigill_signal_handler;
3349 sigemptyset (&sa.sa_mask);
3351 g_assert (syscall (SYS_sigaction, SIGILL, &sa, NULL) != -1);
3353 #ifndef HAVE_BOEHM_GC
3355 sa.sa_handler = sigsegv_signal_handler;
3356 sigemptyset (&sa.sa_mask);
3358 //g_assert (syscall (SYS_sigaction, SIGSEGV, &sa, NULL) != -1);
3362 mono_add_internal_call ("__array_Set", ves_array_set);
3363 mono_add_internal_call ("__array_Get", ves_array_get);
3364 mono_add_internal_call ("__array_Address", ves_array_element_address);
3366 metadata_section = &ms;
3367 InitializeCriticalSection (metadata_section);
3369 lmf_thread_id = TlsAlloc ();
3370 TlsSetValue (lmf_thread_id, NULL);
3371 exc_cleanup_id = TlsAlloc ();
3372 TlsSetValue (exc_cleanup_id, mono_jit_abort);
3373 async_result_id = TlsAlloc ();
3375 mono_install_trampoline (arch_create_jit_trampoline);
3376 mono_install_runtime_class_init (runtime_class_init);
3377 mono_install_runtime_object_init (runtime_object_init);
3378 mono_install_runtime_exec_main (jit_exec_main);
3379 mono_install_handler (arch_get_throw_exception ());
3380 mono_install_runtime_invoke (arch_runtime_invoke);
3382 domain = mono_init (file);
3383 mono_thread_init (domain);
3384 mono_network_init ();
3386 error = mono_verify_corlib ();
3388 fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
3392 mono_delegate_init ();
3394 assembly = mono_domain_assembly_open (domain, file);
3396 fprintf (stderr, "Can not open image %s\n", file);
3401 mono_jit_assembly (assembly);
3402 } else if (compile_class) {
3403 char *cmethod = strrchr (compile_class, ':');
3410 MonoMethodDesc *mdesc;
3412 mdesc = mono_method_desc_new (compile_class, FALSE);
3414 g_error ("Invalid method name '%s'", compile_class);
3415 m = mono_method_desc_search_in_image (mdesc, assembly->image);
3417 g_error ("Cannot find method '%s'", compile_class);
3418 for (j = 0; j < compile_times; ++j) {
3419 code = arch_compile_method (m);
3423 cname = strrchr (compile_class, '.');
3427 cname = compile_class;
3430 class = mono_class_from_name (assembly->image, compile_class, cname);
3432 g_error ("Cannot find class %s.%s", compile_class, cname);
3433 mono_class_init (class);
3434 for (j = 0; j < compile_times; ++j) {
3435 for (i = 0; i < class->method.count; ++i) {
3436 if (class->methods [i]->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
3438 if (class->methods [i]->flags & METHOD_ATTRIBUTE_ABSTRACT)
3441 g_print ("Compiling: %s\n", class->methods [i]->name);
3442 code = arch_compile_method (class->methods [i]);
3449 * skip the program name from the args.
3452 retval = mono_jit_exec (domain, assembly, argc - i, argv + i);
3453 printf ("RESULT: %d\n", retval);
3456 if (mono_debug_handle)
3457 mono_debug_close (mono_debug_handle);
3459 mono_delegate_cleanup ();
3460 mono_network_cleanup ();
3461 mono_thread_cleanup ();
3463 mono_domain_unload (domain, TRUE);
3465 if (mono_jit_stats.enabled) {
3466 g_print ("Mono Jit statistics\n");
3467 g_print ("Compiled methods: %ld\n", mono_jit_stats.methods_compiled);
3468 g_print ("Methods cache lookup: %ld\n", mono_jit_stats.methods_lookups);
3469 g_print ("Method trampolines: %ld\n", mono_jit_stats.method_trampolines);
3470 g_print ("Allocated vars: %ld\n", mono_jit_stats.allocate_var);
3471 g_print ("Analyze stack repeat: %ld\n", mono_jit_stats.analyze_stack_repeat);
3472 g_print ("Compiled CIL code size: %ld\n", mono_jit_stats.cil_code_size);
3473 g_print ("Native code size: %ld\n", mono_jit_stats.native_code_size);
3474 g_print ("Max code size ratio: %.2f (%s::%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
3475 mono_jit_stats.max_ratio_method->klass->name, mono_jit_stats.max_ratio_method->name);
3476 g_print ("Biggest method: %ld (%s::%s)\n", mono_jit_stats.biggest_method_size,
3477 mono_jit_stats.biggest_method->klass->name, mono_jit_stats.biggest_method->name);
3478 g_print ("Code reallocs: %ld\n", mono_jit_stats.code_reallocs);
3479 g_print ("Allocated code size: %ld\n", mono_jit_stats.allocated_code_size);
3482 DeleteCriticalSection (metadata_section);