2 * interp.brg: experimental interpreter code
4 * This is another approach for an interpreter. CIL is translated into another
5 * byte code which can be interpreted more efficiently. First measurements
6 * showed a quite good performance.
8 * We do not develop this further at the moment because of a lack of time.
11 * Dietmar Maurer (dietmar@ximian.com)
13 * (C) 2001 Ximian, Inc. */
18 #include <mono/metadata/blob.h>
19 #include <mono/metadata/metadata.h>
20 #include <mono/metadata/loader.h>
21 #include <mono/metadata/tabledefs.h>
22 #include <mono/metadata/class.h>
26 #define MBTREE_TYPE MBTree
27 #define MBCGEN_TYPE MBCodeGenStatus
28 #define MBCOST_DATA MBCodeGenStatus
29 #define MBALLOC_STATE mono_mempool_alloc (data->mp, sizeof (MBState))
33 typedef struct _MonoInvocation MonoInvocation;
35 typedef void (*MIntFunc) (MonoInvocation *frame);
44 typedef struct _MBTree MBTree;
55 gint32 cli_addr; /* virtual cli address */
56 gint32 addr; /* address of emitted instruction */
57 gint32 first_addr; /* first code address of a tree */
77 struct _MonoInvocation {
78 MonoInvocation *parent; /* parent */
79 MonoInvocation *child;
80 MonoMethod *method; /* parent */
81 stackval *retval; /* parent */
82 void *obj; /* this - parent */
115 #define INIT_FRAME(frame,parent_frame,obj_this,method_args,method_retval,mono_method) \
117 (frame)->parent = (parent_frame); \
118 (frame)->obj = (obj_this); \
119 (frame)->args = (method_args); \
120 (frame)->retval = (method_retval); \
121 (frame)->method = (mono_method); \
124 #define COMMAND(c,name) do { *(c)++ = name; } while (0)
126 #define MB_OPT_LEVEL 1
128 #if MB_OPT_LEVEL == 0
129 #define MB_USE_OPT1(c) 65535
130 #define MB_USE_OPT2(c) 65535
132 #if MB_OPT_LEVEL == 1
133 #define MB_USE_OPT1(c) c
134 #define MB_USE_OPT2(c) 65535
136 #if MB_OPT_LEVEL >= 2
137 #define MB_USE_OPT1(c) c
138 #define MB_USE_OPT2(c) c
144 # terminal definitions
148 %term CONST_I4 CONST_I8 CONST_R4 CONST_R8
149 %term LDIND_I1 LDIND_U1 LDIND_I2 LDIND_U2 LDIND_I4 LDIND_I8 LDIND_R4 LDIND_R8
151 %term STIND_I1 STIND_I2 STIND_I4 STIND_I8 STIND_R4 STIND_R8
152 %term ADDR_L ADDR_A ADDR_G ARG ARG_END CALL_I4 CALL_I8 CALL_R8
153 %term BREAK SWITCH BR RET RETV
154 %term ADD SUB MUL DIV DIV_UN REM REM_UN AND OR XOR SHL SHR SHR_UN NEG NOT
155 %term BLT BLT_UN BEQ BNE_UN BRTRUE BRFALSE BGE BGE_UN BLE BLE_UN BGT BGT_UN
156 %term CONV_I4 CONV_I1 CONV_I2 CONV_I8 CONV_R8
168 COMMAND (s->code, IC_CONST_I4);
169 *((gint32*)s->code)++ = tree->data.i;
176 COMMAND (s->code, IC_ADDR_L);
177 *((gint32*)s->code)++ = tree->data.i;
181 COMMAND (s->code, IC_ADDR_A);
182 *((gint32*)s->code)++ = tree->data.i;
185 reg: LDIND_I4 (reg) {
186 COMMAND (s->code, IC_LDIND_I4);
189 reg: LDIND_I4 (ADDR_L) "MB_USE_OPT1(0)" {
190 COMMAND (s->code, IC_LDIND_LOC_I4);
191 *((gint32*)s->code)++ = tree->left->data.i;
194 reg: LDIND_I4 (ADDR_A) "MB_USE_OPT1(0)" {
195 COMMAND (s->code, IC_LDIND_ARG_I4);
196 *((gint32*)s->code)++ = tree->left->data.i;
199 reg: MUL (reg, reg) {
200 COMMAND (s->code, IC_MUL_I4);
204 reg: ADD (reg, reg) {
205 COMMAND (s->code, IC_ADD_I4);
208 reg: SUB (reg, reg) {
209 COMMAND (s->code, IC_SUB_I4);
212 # just an optimisations
213 reg: SUB (LDIND_I4 (ADDR_A), CONST_I4) "MB_USE_OPT1(0)" {
214 COMMAND (s->code, IC_SUB_ARG_CI4);
215 *((gint32*)s->code)++ = tree->left->left->data.i;
216 *((gint32*)s->code)++ = tree->right->data.i;
219 stmt: STIND_I4 (reg, reg) {
220 COMMAND (s->code, IC_STIND_I4);
223 stmt: STIND_I4 (ADDR_L, reg) "MB_USE_OPT1(0)" {
224 COMMAND (s->code, IC_STIND_LOC_I4);
225 *((gint32*)s->code)++ = tree->left->data.i;
231 COMMAND (s->code, IC_BR);
232 *((gint32*)s->code)++ = tree->data.i - 5;
235 stmt: BLT (reg, reg) 1 {
238 COMMAND (s->code, IC_BLT_I4);
239 *((gint32*)s->code)++ = tree->data.i - 5;
242 stmt: BEQ (reg, reg) {
245 COMMAND (s->code, IC_BEQ_I4);
246 *((gint32*)s->code)++ = tree->data.i - 5;
249 stmt: BGE (reg, reg) 1 {
252 COMMAND (s->code, IC_BGE_I4);
253 *((gint32*)s->code)++ = tree->data.i - 5;
256 stmt: BGE (reg, CONST_I4) "MB_USE_OPT1(0)" {
259 COMMAND (s->code, IC_BGE_I4_C);
260 *((gint32*)s->code)++ = tree->right->data.i;
261 *((gint32*)s->code)++ = tree->data.i - 9;
264 stmt: BRTRUE (reg) 1 {
267 COMMAND (s->code, IC_BRTRUE_I4);
268 *((gint32*)s->code)++ = tree->data.i - 5;
271 stmt: BRTRUE (LDIND_I4 (ADDR_L)) "MB_USE_OPT1(0)" {
274 COMMAND (s->code, IC_BRTRUE_LOC_I4);
275 *((gint32*)s->code)++ = tree->left->left->data.i;
276 *((gint32*)s->code)++ = tree->data.i - 9;
280 COMMAND (s->code, IC_RETV_I4);
284 COMMAND (s->code, IC_RET);
287 argl: ARG (argl, reg) {
288 COMMAND (s->code, IC_PUSH_I4);
293 reg: CALL_I4 (argl) {
294 COMMAND (s->code, IC_CALL_I4);
295 *((gint32*)s->code)++ = tree->data.i;
298 stmt: CALL_I4 (argl) {
299 COMMAND (s->code, IC_CALL_I4);
300 *((gint32*)s->code)++ = tree->data.i;
309 mono_ctree_new (MonoMemPool *mp, int op, MBTree *left, MBTree *right)
311 MBTree *t = mono_mempool_alloc0 (mp, sizeof (MBTree));
321 mono_ctree_new_leaf (MonoMemPool *mp, int op)
323 return mono_ctree_new (mp, op, NULL, NULL);
327 interp_exec_method (MonoInvocation *frame)
329 MonoInvocation child_frame;
330 MonoMethodHeader *header;
331 guint8 *ip, *ap, *args;
332 register stackval *sp;
334 d(printf ("EXEC METHOD %p\n", frame->args));
336 g_assert (frame->method->addr != NULL);
338 if (!frame->method->klass->inited)
339 mono_jit_init_class (frame->method->klass);
341 child_frame.parent = frame;
343 header = ((MonoMethodNormal *)frame->method)->header;
345 ip = frame->method->addr;
347 sp = frame->stack = alloca (sizeof (stackval) * header->max_stack);
349 args = ap = alloca (256); // fixme: use max args size
351 if (header->num_locals) {
352 frame->locals = alloca (header->locals_size);
353 memset (frame->locals, 0, header->locals_size);
354 frame->locals += header->locals_size;
361 sp->data.i = *((gint32*)ip);
362 d(printf ("IC_CONST_I4 %d:\n", sp->data.i));
368 d(printf ("IC_ADDR_L: %p\n", sp));
369 sp->data.p = frame->locals + *((gint32*)ip);
375 sp->data.p = frame->args + *((gint32*)ip);
376 d(printf ("IC_ADDR_A: %p\n", sp->data.p));
383 sp->data.i = *(gint32*)sp->data.p;
384 d(printf ("IC_LDIND_I4: %p %d\n", sp->data.p, sp->data.i));
388 case IC_LDIND_LOC_I4: {
389 gint32 *p = (gint32 *)frame->locals + *((gint32*)ip);
391 d(printf ("IC_LDIND_LOC_I4: %p %d\n", p, sp->data.i));
396 case IC_LDIND_ARG_I4: {
397 gint32 *p = (gint32 *)frame->args + *((gint32*)ip);
399 d(printf ("IC_LDIND_LOC_I4: %p %d\n", p, sp->data.i));
406 d(printf ("IC_STIND_I4: %p %d\n", sp->data.p, sp [1].data.i));
407 *(gint32*)sp->data.p = sp [1].data.i;
410 case IC_STIND_LOC_I4: {
411 gint32 *p = (gint32 *)frame->locals + *((gint32*)ip);
413 d(printf ("IC_STIND_LOC_I4: %p %d\n", p, sp->data.i));
419 d(printf ("IC_MUL_I4:\n"));
420 g_assert_not_reached ();
425 sp->data.i = sp [0].data.i + sp [1].data.i;
426 d(printf ("IC_ADD_I4: %d\n", sp->data.i));
432 sp->data.i = sp [0].data.i - sp [1].data.i;
433 d(printf ("IC_SUB_I4: %d\n", sp->data.i));
437 case IC_ADD_LOC_LOC_I4: {
438 gint32 *p1 = (gint32 *)frame->args + *((gint32*)ip);
439 gint32 *p2 = (gint32 *)frame->args + *((gint32*)ip+1);
441 sp->data.i = *p1 + *p2;
442 d(printf ("IC_ADD_LOC_LOC_I4: %d\n", sp->data.i));
448 case IC_SUB_ARG_CI4: {
449 gint32 *p = (gint32 *)frame->args + *((gint32*)ip);
450 sp->data.i = *p - *(((gint32*)ip) + 1);
451 d(printf ("IC_SUB_ARG_CI4: %d\n", sp->data.i));
458 d(printf ("IC_BR:\n"));
459 ip += 4 + *((gint32*)ip);
463 d(printf ("IC_BLT_I4:\n"));
465 g_assert_not_reached ();
470 d(printf ("IC_BRTRUE_I4: (%d) %d\n", sp [0].data.i, *((gint32*)ip)));
473 ip += 4 + *((gint32*)ip);
478 case IC_BRTRUE_LOC_I4: {
479 gint32 *p = (gint32 *)frame->locals + *((gint32*)ip);
481 d(printf ("IC_BRTRUE_LOC_I4: %d %d\n", p, *((gint32*)ip+1)));
484 ip += 8 + *((gint32*)ip+1);
491 d(printf ("IC_BEQ_I4: (%d == %d) %d\n", sp [0].data.i, sp [1].data.i, *((gint32*)ip)));
493 if (sp [0].data.i == sp [1].data.i)
494 ip += 4 + *((gint32*)ip);
501 d(printf ("IC_BGE_I4: (%d >= %d) %d\n", sp [0].data.i, sp [1].data.i, *((gint32*)ip)));
503 if (sp [0].data.i >= sp [1].data.i)
504 ip += 4 + *((gint32*)ip);
511 d(printf ("IC_BGE_I4: (%d >= %d) %d\n", sp [0].data.i,
512 *((gint32*)ip), *(((gint32*)ip) + 1)));
513 if (sp [0].data.i >= *((gint32*)ip))
514 ip += 8 + *(((gint32*)ip) + 1);
520 d(printf ("IC_RET:\n"));
526 d(printf ("IC_RETV_I4: %d\n", sp->data.i));
527 frame->retval->data.i = sp->data.i;
533 *((gint32*)ap) = sp->data.i;
534 d(printf ("IC_PUSH: %d\n", sp->data.i));
539 MonoMethod *m = (MonoMethod *)*((gint32*)ip);
543 arch_compile_method (m);
547 INIT_FRAME (&child_frame, NULL, NULL, args, sp, m);
549 interp_exec_method (&child_frame);
550 d(printf ("RESULT: %d\n", sp->data.i));
558 g_warning ("unknown interpreter opcode %d\n", *(ip -1));
559 g_assert_not_reached ();
567 get_address (GPtrArray *forest, gint32 cli_addr, gint base, gint len)
575 /* skip trees with cli_addr == -1 */
576 while ((t1 = (MBTree *) g_ptr_array_index (forest, pos)) &&
577 t1->cli_addr == -1 && ind) {
582 if (t1->cli_addr == cli_addr) {
584 return t1->first_addr;
590 if (t1->cli_addr > cli_addr) {
591 return get_address (forest, cli_addr, base, ind);
594 return get_address (forest, cli_addr, base + ind, len - ind);
599 compute_branches (MBCodeGenStatus *s)
601 GPtrArray *forest = s->forest;
602 const int top = forest->len;
609 for (i = 0; i < top; i++) {
610 MBTree *t1 = (MBTree *) g_ptr_array_index (forest, i);
614 if ((i + 1) < forest->len) {
615 MBTree *t2 = (MBTree *) g_ptr_array_index (forest, i + 1);
619 addr = get_address (forest, t1->data.i, 0, forest->len);
621 g_error ("address 0x%x not found at IL_%04x",
622 t1->data.i, t1->cli_addr);
624 t1->data.i = addr - t1->addr;
626 /* emit the jump instruction again to update addresses */
627 s->code = s->start + t1->addr;
628 ((MBEmitFunc)t1->emit) (t1, s);
637 tree_emit (int goal, MBCodeGenStatus *s, MBTree *tree)
640 int i, ern = mono_burg_rule (tree->state, goal);
641 guint16 *nts = mono_burg_nts [ern];
643 mono_burg_kids (tree, ern, kids);
645 for (i = 0; nts [i]; i++)
646 tree_emit (nts [i], s, kids [i]);
648 tree->addr = s->code - s->start;
650 if ((tree->emit = mono_burg_func [ern]))
651 ((MBEmitFunc)tree->emit) (tree, s);
655 forest_emit (MBCodeGenStatus *s)
657 GPtrArray *forest = s->forest;
658 const int top = forest->len;
661 for (i = 0; i < top; i++) {
662 MBTree *t1 = (MBTree *) g_ptr_array_index (forest, i);
663 t1->first_addr = s->code - s->start;
664 tree_emit (1, s, t1);
669 emit_method (MonoMethod *method, MBCodeGenStatus *s)
671 method->addr = s->start = s->code = g_malloc (1024);
673 if (mono_jit_dump_forest)
674 mono_print_forest (s->forest);
676 mono_jit_label_forest (s);
679 compute_branches (s);
682 //if (mono_jit_dump_asm)
683 // mono_disassemble_code (s->start, s->code - s->start);
687 arch_compile_method (MonoMethod *method)
689 MBCodeGenStatus cgstat;
690 MonoMemPool *mp = mono_mempool_new ();
693 g_assert (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL));
694 g_assert (!(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL));
696 printf ("Start JIT compilation of %s\n", method->name);
698 cgstat.forest = mono_create_forest (method, mp, &locals_size);
702 emit_method (method, &cgstat);
704 g_ptr_array_free (cgstat.forest, TRUE);
706 mono_mempool_destroy (mp);
712 arch_create_jit_trampoline (MonoMethod *method)
719 arch_exec (MonoMethod *method)
724 arch_compile_method (method);
726 INIT_FRAME (&call, NULL, NULL, NULL, &result, method);
728 interp_exec_method (&call);
730 return result.data.i;