2001-12-17 Dietmar Maurer <dietmar@ximian.com>
[mono.git] / mono / jit / emit-x86.c
1 /*
2  * emit-x86.c: Support functions for emitting x86 code
3  *
4  * Authors:
5  *   Dietmar Maurer (dietmar@ximian.com)
6  *   Miguel de Icaza (miguel@ximian.com)
7  *
8  * (C) 2001 Ximian, Inc.
9  */
10
11 #include <config.h>
12 #include <glib.h>
13
14 #include <mono/metadata/assembly.h>
15 #include <mono/metadata/loader.h>
16 #include <mono/metadata/cil-coff.h>
17 #include <mono/metadata/tabledefs.h>
18 #include <mono/metadata/class.h>
19 #include <mono/metadata/mono-endian.h>
20 #include <mono/arch/x86/x86-codegen.h>
21
22 #include "jit.h"
23 #include "codegen.h"
24 #include "debug.h"
25
26 static void
27 enter_method (MonoMethod *method, gpointer ebp)
28 {
29         int i, j;
30         MonoClass *class;
31         MonoObject *o;
32
33         printf ("ENTER: %s.%s::%s\n(", method->klass->name_space,
34                 method->klass->name, method->name);
35
36         ebp += 8;
37
38         if (ISSTRUCT (method->signature->ret)) {
39                 int size, align;
40                 
41                 g_assert (!method->signature->ret->byref);
42
43                 size = mono_type_size (method->signature->ret, &align);
44
45                 printf ("VALUERET:%p, ", *((gpointer *)ebp));
46                 ebp += sizeof (gpointer);
47         }
48
49         if (method->signature->hasthis) {
50                 if (method->klass->valuetype) {
51                         printf ("value:%p, ", *((gpointer *)ebp));
52                 } else {
53                         o = *((MonoObject **)ebp);
54
55                         g_assert (o);
56
57                         class = o->klass;
58
59                         if (class == mono_defaults.string_class) {
60                                 printf ("this:[STRING:%p:%s], ", o, mono_string_to_utf8 ((MonoString *)o));
61                         } else {
62                                 printf ("this:%p[%s.%s], ", o, class->name_space, class->name);
63                         }
64                 }
65                 ebp += sizeof (gpointer);
66         }
67
68         for (i = 0; i < method->signature->param_count; ++i) {
69                 MonoType *type = method->signature->params [i];
70                 int size, align;
71                 size = mono_type_size (type, &align);
72
73                 switch (type->type) {
74                 case MONO_TYPE_BOOLEAN:
75                 case MONO_TYPE_CHAR:
76                 case MONO_TYPE_I1:
77                 case MONO_TYPE_U1:
78                 case MONO_TYPE_I2:
79                 case MONO_TYPE_U2:
80                 case MONO_TYPE_I4:
81                 case MONO_TYPE_U4:
82                 case MONO_TYPE_I:
83                 case MONO_TYPE_U:
84                         printf ("%d, ", *((int *)(ebp)));
85                         break;
86                 case MONO_TYPE_STRING: {
87                         MonoString *s = *((MonoString **)ebp);
88                         if (s) {
89                                 g_assert (((MonoObject *)s)->klass == mono_defaults.string_class);
90                                 printf ("[STRING:%p:%s], ", s, mono_string_to_utf8 (s));
91                         } else 
92                                 printf ("[STRING:null], ");
93                         break;
94                 }
95                 case MONO_TYPE_CLASS:
96                 case MONO_TYPE_OBJECT: {
97                         o = *((MonoObject **)ebp);
98                         if (o) {
99                                 class = o->klass;
100                                 if (class == mono_defaults.string_class) {
101                                         printf ("[STRING:%p:%s], ", o, mono_string_to_utf8 ((MonoString *)o));
102                                 } else if (class == mono_defaults.int32_class) {
103                                         printf ("[INT32:%p:%d], ", o, *(gint32 *)((gpointer)o + sizeof (MonoObject)));
104                                 } else
105                                         printf ("[%s.%s:%p], ", class->name_space, class->name, o);
106                         } else {
107                                 printf ("%p, ", *((gpointer *)(ebp)));                          
108                         }
109                         break;
110                 }
111                 case MONO_TYPE_PTR:
112                 case MONO_TYPE_FNPTR:
113                 case MONO_TYPE_ARRAY:
114                 case MONO_TYPE_SZARRAY:
115                         printf ("%p, ", *((gpointer *)(ebp)));
116                         break;
117                 case MONO_TYPE_I8:
118                         printf ("%lld, ", *((gint64 *)(ebp)));
119                         break;
120                 case MONO_TYPE_R4:
121                         printf ("%f, ", *((float *)(ebp)));
122                         break;
123                 case MONO_TYPE_R8:
124                         printf ("%f, ", *((double *)(ebp)));
125                         break;
126                 case MONO_TYPE_VALUETYPE: 
127                         printf ("[");
128                         for (j = 0; j < size; j++)
129                                 printf ("%02x,", *((guint8*)ebp +j));
130                         printf ("], ");
131                         break;
132                 default:
133                         printf ("XX, ");
134                 }
135
136                 ebp += size + 3;
137                 ebp = (gpointer)((unsigned)ebp & ~(3));
138         }
139
140         printf (")\n");
141 }
142
143 static void
144 leave_method (MonoMethod *method, int edx, int eax, double test)
145 {
146         gint64 l;
147
148         printf ("LEAVE: %s.%s::%s ", method->klass->name_space,
149                 method->klass->name, method->name);
150
151         switch (method->signature->ret->type) {
152         case MONO_TYPE_VOID:
153                 break;
154         case MONO_TYPE_BOOLEAN:
155                 if (eax)
156                         printf ("TRUE:%d", eax);
157                 else 
158                         printf ("FALSE");
159                         
160                 break;
161         case MONO_TYPE_CHAR:
162         case MONO_TYPE_I1:
163         case MONO_TYPE_U1:
164         case MONO_TYPE_I2:
165         case MONO_TYPE_U2:
166         case MONO_TYPE_I4:
167         case MONO_TYPE_U4:
168         case MONO_TYPE_I:
169         case MONO_TYPE_U:
170                 printf ("EAX=%d", eax);
171                 break;
172         case MONO_TYPE_STRING: {
173                 MonoString *s = (MonoString *)eax;
174
175                 if (s) {
176                         g_assert (((MonoObject *)s)->klass == mono_defaults.string_class);
177                         printf ("[STRING:%p:%s]", s, mono_string_to_utf8 (s));
178                 } else 
179                         printf ("[STRING:null], ");
180                 break;
181         }
182         case MONO_TYPE_OBJECT: {
183                 MonoObject *o = (MonoObject *)eax;
184                 
185                 if (o->klass == mono_defaults.boolean_class) {
186                         printf ("[BOOLEAN:%p:%d]", o, *((guint8 *)o + sizeof (MonoObject)));            
187                 } else if  (o->klass == mono_defaults.int32_class) {
188                         printf ("[INT32:%p:%d]", o, *((gint32 *)((gpointer)o + sizeof (MonoObject))));  
189                 } else {
190                         if (o)
191                                 printf ("[%s.%s:%p]", o->klass->name_space, o->klass->name, o);
192                         else
193                                 printf ("[OBJECT:%p]", (gpointer)eax);
194                 }
195                 break;
196         }
197         case MONO_TYPE_CLASS:
198         case MONO_TYPE_PTR:
199         case MONO_TYPE_FNPTR:
200         case MONO_TYPE_ARRAY:
201         case MONO_TYPE_SZARRAY:
202                 printf ("EAX=%p", (gpointer)eax);
203                 break;
204         case MONO_TYPE_I8:
205                 *((gint32 *)&l) = eax;
206                 *((gint32 *)&l + 1) = edx;
207                 printf ("EAX/EDX=%lld", l);
208                 break;
209         case MONO_TYPE_R8:
210                 printf ("FP=%f\n", test);
211                 break;
212         default:
213                 printf ("(unknown return type)");
214         }
215
216         printf ("\n");
217 }
218
219 /**
220  * arch_emit_prologue:
221  * @cfg: pointer to status information
222  *
223  * Emits the function prolog.
224  */
225 static void
226 arch_emit_prologue (MonoFlowGraph *cfg)
227 {
228         x86_push_reg (cfg->code, X86_EBP);
229         x86_mov_reg_reg (cfg->code, X86_EBP, X86_ESP, 4);
230
231         if (cfg->locals_size)
232                 x86_alu_reg_imm (cfg->code, X86_SUB, X86_ESP, cfg->locals_size);
233
234         if (mono_regset_reg_used (cfg->rs, X86_EBX)) 
235                 x86_push_reg (cfg->code, X86_EBX);
236
237         if (mono_regset_reg_used (cfg->rs, X86_EDI)) 
238                 x86_push_reg (cfg->code, X86_EDI);
239
240         if (mono_regset_reg_used (cfg->rs, X86_ESI))
241                 x86_push_reg (cfg->code, X86_ESI);
242
243         if (mono_jit_trace_calls) {
244                 x86_push_reg (cfg->code, X86_EBP);
245                 x86_push_imm (cfg->code, cfg->method);
246                 x86_mov_reg_imm (cfg->code, X86_EAX, enter_method);
247                 x86_call_reg (cfg->code, X86_EAX);
248                 x86_alu_reg_imm (cfg->code, X86_ADD, X86_ESP, 8);
249         }
250 }
251
252 /**
253  * arch_emit_epilogue:
254  * @cfg: pointer to status information
255  *
256  * Emits the function epilog.
257  */
258 static void
259 arch_emit_epilogue (MonoFlowGraph *cfg)
260 {
261         if (mono_jit_trace_calls) {
262                 x86_fld_reg (cfg->code, 0);
263                 x86_alu_reg_imm (cfg->code, X86_SUB, X86_ESP, 8);
264                 x86_fst_membase (cfg->code, X86_ESP, 0, TRUE, TRUE);
265                 x86_push_reg (cfg->code, X86_EAX);
266                 x86_push_reg (cfg->code, X86_EDX);
267                 x86_push_imm (cfg->code, cfg->method);
268                 x86_mov_reg_imm (cfg->code, X86_EAX, leave_method);
269                 x86_call_reg (cfg->code, X86_EAX);
270                 x86_alu_reg_imm (cfg->code, X86_ADD, X86_ESP, 4);
271                 x86_pop_reg (cfg->code, X86_EDX);
272                 x86_pop_reg (cfg->code, X86_EAX);
273                 x86_alu_reg_imm (cfg->code, X86_ADD, X86_ESP, 8);
274         }
275
276         if (mono_regset_reg_used (cfg->rs, X86_ESI))
277                 x86_pop_reg (cfg->code, X86_ESI);
278
279         if (mono_regset_reg_used (cfg->rs, X86_EDI))
280                 x86_pop_reg (cfg->code, X86_EDI);
281
282         if (mono_regset_reg_used (cfg->rs, X86_EBX))
283                 x86_pop_reg (cfg->code, X86_EBX);
284
285         x86_leave (cfg->code);
286         x86_ret (cfg->code);
287 }
288
289 /*
290  * get_unbox_trampoline:
291  * @m: method pointer
292  *
293  * when value type methods are called through the vtable we need to unbox the
294  * this argument. This method returns a pointer to a trampoline which does
295  * unboxing before calling the method
296  */
297 static gpointer
298 get_unbox_trampoline (MonoMethod *m)
299 {
300         gpointer p = arch_compile_method (m);
301         guint8 *code, *start;
302         int this_pos = 4;
303
304         if (!m->signature->ret->byref && m->signature->ret->type == MONO_TYPE_VALUETYPE)
305                 this_pos = 8;
306             
307         start = code = g_malloc (16);
308
309         x86_alu_membase_imm (code, X86_ADD, X86_ESP, this_pos, sizeof (MonoObject));
310         x86_jump_code (code, p);
311         g_assert ((code - start) < 16);
312
313         return start;
314 }
315
316 /**
317  * x86_magic_trampoline:
318  * @eax: saved x86 register 
319  * @ecx: saved x86 register 
320  * @edx: saved x86 register 
321  * @esi: saved x86 register 
322  * @edi: saved x86 register 
323  * @ebx: saved x86 register
324  * @code: pointer into caller code
325  * @method: the method to translate
326  *
327  * This method is called by the trampoline functions for virtual
328  * methods. It inspects the caller code to find the address of the
329  * vtable slot, then calls the JIT compiler and writes the address
330  * of the compiled method back to the vtable. All virtual methods 
331  * are called with: x86_call_membase (inst, basereg, disp). We always
332  * use 32 bit displacement to ensure that the length of the call 
333  * instruction is 6 bytes. We need to get the value of the basereg 
334  * and the constant displacement.
335  */
336 static gpointer
337 x86_magic_trampoline (int eax, int ecx, int edx, int esi, int edi, 
338                       int ebx, guint8 *code, MonoMethod *m)
339 {
340         guint8 ab, reg;
341         gint32 disp;
342         gpointer o;
343
344         /* go to the start of the call instruction */
345         code -= 6;
346         g_assert (*code == 0xff);
347
348         code++;
349         ab = *code;
350         g_assert ((ab >> 6) == 2);
351         
352         /* extract the register number containing the address */
353         reg = ab & 0x07;
354         code++;
355
356         /* extract the displacement */
357         disp = *((gint32*)code);
358
359         switch (reg) {
360         case X86_EAX:
361                 o = (gpointer)eax;
362                 break;
363         case X86_EDX:
364                 o = (gpointer)edx;
365                 break;
366         case X86_ECX:
367                 o = (gpointer)ecx;
368                 break;
369         case X86_ESI:
370                 o = (gpointer)esi;
371                 break;
372         case X86_EDI:
373                 o = (gpointer)edi;
374                 break;
375         case X86_EBX:
376                 o = (gpointer)ebx;
377                 break;
378         default:
379                 g_assert_not_reached ();
380         }
381
382         o += disp;
383
384         if (m->klass->valuetype) {
385                 return *((gpointer *)o) = get_unbox_trampoline (m);
386         } else
387                 return *((gpointer *)o) = arch_compile_method (m);
388 }
389
390 /**
391  * arch_create_jit_trampoline:
392  * @method: pointer to the method info
393  *
394  * Creates a trampoline function for virtual methods. If the created
395  * code is called it first starts JIT compilation of method,
396  * and then calls the newly created method. I also replaces the
397  * corresponding vtable entry (see x86_magic_trampoline).
398  * 
399  * Returns: a pointer to the newly created code 
400  */
401 gpointer
402 arch_create_jit_trampoline (MonoMethod *method)
403 {
404         guint8 *code, *buf;
405         static guint8 *vc = NULL;
406
407         if (method->addr)
408                 return method->addr;
409
410         if (!vc) {
411                 vc = buf = g_malloc (24);
412
413                 /* push the return address onto the stack */
414                 x86_push_membase (buf, X86_ESP, 4);
415
416                 /* save all register values */
417                 x86_push_reg (buf, X86_EBX);
418                 x86_push_reg (buf, X86_EDI);
419                 x86_push_reg (buf, X86_ESI);
420                 x86_push_reg (buf, X86_EDX);
421                 x86_push_reg (buf, X86_ECX);
422                 x86_push_reg (buf, X86_EAX);
423
424                 x86_call_code (buf, x86_magic_trampoline);
425                 x86_alu_reg_imm (buf, X86_ADD, X86_ESP, 8*4);
426
427                 /* call the compiled method */
428                 x86_jump_reg (buf, X86_EAX);
429
430                 g_assert ((buf - vc) <= 24);
431         }
432
433         code = buf = g_malloc (16);
434         x86_push_imm (buf, method);
435         x86_jump_code (buf, vc);
436         g_assert ((buf - code) <= 16);
437
438         return code;
439 }
440
441 /**
442  * arch_create_simple_jit_trampoline:
443  * @method: pointer to the method info
444  *
445  * Creates a trampoline function for method. If the created
446  * code is called it first starts JIT compilation of method,
447  * and then calls the newly created method. I also replaces the
448  * address in method->addr with the result of the JIT 
449  * compilation step (in arch_compile_method).
450  * 
451  * Returns: a pointer to the newly created code 
452  */
453 gpointer
454 arch_create_simple_jit_trampoline (MonoMethod *method)
455 {
456         guint8 *code, *buf;
457
458         if (method->addr)
459                 return method->addr;
460
461         /* we never free the allocated code buffer */
462         code = buf = g_malloc (16);
463         x86_push_imm (buf, method);
464         x86_call_code (buf, arch_compile_method);
465         x86_alu_reg_imm (buf, X86_ADD, X86_ESP, 4);
466         /* jump to the compiled method */
467         x86_jump_reg (buf, X86_EAX);
468         g_assert ((buf - code) < 16);
469
470         return code;
471 }
472
473 static void
474 mono_label_cfg (MonoFlowGraph *cfg)
475 {
476         int i, j;
477         
478         for (i = 0; i < cfg->block_count; i++) {
479                 GPtrArray *forest = cfg->bblocks [i].forest;
480                 const int top = forest->len;
481
482                 for (j = 0; j < top; j++) {
483                         MBTree *t1 = (MBTree *) g_ptr_array_index (forest, j);
484                         MBState *mbstate;
485
486                         mbstate =  mono_burg_label (t1, cfg);
487                         if (!mbstate) {
488                                 cfg->invalid = 1;
489                                 if (mono_debug_handle)
490                                         return;
491                                 g_warning ("tree does not match");
492                                 mono_print_ctree (t1); printf ("\n\n");
493
494                                 mono_print_forest (forest);
495                                 g_assert_not_reached ();
496                         }
497                 }
498         }
499 }
500
501 static void
502 tree_preallocate_regs (MBTree *tree, int goal, MonoRegSet *rs) 
503 {
504         switch (tree->op) {
505         case MB_TERM_CALL_I4:
506         case MB_TERM_CALL_I8:
507         case MB_TERM_CALL_R8:
508 //      case MB_TERM_CALL_VOID :
509                 tree->reg1 = mono_regset_alloc_reg (rs, X86_EAX, tree->exclude_mask);
510                 tree->reg2 = mono_regset_alloc_reg (rs, X86_EDX, tree->exclude_mask);
511                 tree->reg3 = mono_regset_alloc_reg (rs, X86_ECX, tree->exclude_mask);
512                 return;
513         default: break;
514         }
515
516         switch (goal) {
517         case MB_NTERM_reg:
518         case MB_NTERM_lreg: {
519                 switch (tree->op) {
520                 case MB_TERM_SHL:
521                 case MB_TERM_SHR:
522                 case MB_TERM_SHR_UN:
523                         tree->exclude_mask |= (1 << X86_ECX);
524                         tree->left->exclude_mask |= (1 << X86_ECX);
525                         break;
526                 case MB_TERM_DIV:
527                 case MB_TERM_DIV_UN:
528                 case MB_TERM_REM:
529                 case MB_TERM_REM_UN:
530                         tree->reg1 = mono_regset_alloc_reg (rs, X86_EAX, tree->exclude_mask);
531                         tree->reg2 = mono_regset_alloc_reg (rs, X86_EDX, tree->exclude_mask);
532                         if (goal == MB_NTERM_reg) {
533                                 tree->left->exclude_mask |= (1 << X86_EDX);
534                                 tree->right->exclude_mask |= (1 << X86_EDX) | (1 << X86_EAX);
535                         }
536                         break;
537                 default:
538                         break;
539                 }
540                 break;
541         }
542         default:
543                 break;
544         }
545 }
546
547 static void
548 tree_allocate_regs (MBTree *tree, int goal, MonoRegSet *rs) 
549 {
550         MBTree *kids[10];
551         int ern = mono_burg_rule (tree->state, goal);
552         guint16 *nts = mono_burg_nts [ern];
553         int i;
554         
555         mono_burg_kids (tree, ern, kids);
556
557         //printf ("RALLOC START %d %p %d\n",  tree->op, rs->free_mask, goal);
558
559         if (nts [0] && kids [0] == tree) {
560                 /* chain rule */
561                 tree_allocate_regs (kids [0], nts [0], rs);
562                 return;
563         }
564
565         for (i = 0; nts [i]; i++)
566                 tree_preallocate_regs (kids [i], nts [i], rs);
567
568         for (i = 0; nts [i]; i++)
569                 tree_allocate_regs (kids [i], nts [i], rs);
570
571         for (i = 0; nts [i]; i++) {
572                 mono_regset_free_reg (rs, kids [i]->reg1);
573                 mono_regset_free_reg (rs, kids [i]->reg2);
574                 mono_regset_free_reg (rs, kids [i]->reg3);
575         }
576
577         switch (goal) {
578         case MB_NTERM_reg:
579                 if (tree->reg1 < 0) { 
580                         tree->reg1 = mono_regset_alloc_reg (rs, -1, tree->exclude_mask);
581                         g_assert (tree->reg1 != -1);
582                 }
583                 break;
584
585         case MB_NTERM_lreg:
586                 if (tree->reg1 < 0) { 
587                         tree->reg1 = mono_regset_alloc_reg (rs, -1, tree->exclude_mask);
588                         g_assert (tree->reg1 != -1);
589                 }
590                 if (tree->reg2 < 0) { 
591                         tree->reg2 = mono_regset_alloc_reg (rs, -1, tree->exclude_mask);
592                         g_assert (tree->reg2 != -1);
593                 }
594                 break;
595
596         case MB_NTERM_freg:
597                 /* fixme: allocate floating point registers */
598                 break;
599       
600         case MB_NTERM_addr:
601                 if (tree->op == MB_TERM_ADD) {
602                         tree->reg1 = mono_regset_alloc_reg (rs, tree->left->reg1, tree->exclude_mask);
603                         tree->reg2 = mono_regset_alloc_reg (rs, tree->right->reg1, tree->exclude_mask);
604                 }
605                 break;
606                 
607         case MB_NTERM_base:
608                 if (tree->op == MB_TERM_ADD) {
609                         tree->reg1 = mono_regset_alloc_reg (rs, tree->left->reg1, tree->exclude_mask);
610                 }
611                 break;
612                
613         case MB_NTERM_index:
614                 if (tree->op == MB_TERM_SHL ||
615                     tree->op == MB_TERM_MUL) {
616                         tree->reg1 = mono_regset_alloc_reg (rs, tree->left->reg1, tree->exclude_mask);
617                 }
618                 break;
619                
620         default:
621                 /* do nothing */
622         }
623
624         //printf ("RALLOC END %d %p\n",  tree->op, rs->free_mask);
625         tree->emit = mono_burg_func [ern];
626 }
627
628 static void
629 arch_allocate_regs (MonoFlowGraph *cfg)
630 {
631         int i, j;
632         
633         for (i = 0; i < cfg->block_count; i++) {
634                 GPtrArray *forest = cfg->bblocks [i].forest;
635                 const int top = forest->len;
636
637                 for (j = 0; j < top; j++) {
638                         MBTree *t1 = (MBTree *) g_ptr_array_index (forest, j);
639                         //printf ("AREGSTART %d:%d %p\n", i, j, cfg->rs->free_mask);
640                         tree_allocate_regs (t1, 1, cfg->rs);
641                         //printf ("AREGENDT %d:%d %p\n", i, j, cfg->rs->free_mask);
642                         g_assert (cfg->rs->free_mask == 0xffffffff);
643                 }
644         }
645 }
646
647 static void
648 tree_emit (int goal, MonoFlowGraph *cfg, MBTree *tree) 
649 {
650         MBTree *kids[10];
651         int i, ern = mono_burg_rule (tree->state, goal);
652         guint16 *nts = mono_burg_nts [ern];
653         MBEmitFunc emit;
654         int offset;
655
656         mono_burg_kids (tree, ern, kids);
657
658         for (i = 0; nts [i]; i++) 
659                 tree_emit (nts [i], cfg, kids [i]);
660
661         tree->addr = offset = cfg->code - cfg->start;
662
663         // we assume an instruction uses a maximum of 128 bytes
664         if ((cfg->code_size - offset) <= 128) {
665                 int add = MIN ((cfg->code_size * 2), 1024);
666
667                 cfg->code_size += add;
668                 cfg->start = g_realloc (cfg->start, cfg->code_size);
669                 g_assert (cfg->start);
670                 cfg->code = cfg->start + offset;
671         }
672
673         if ((emit = mono_burg_func [ern]))
674                 emit (tree, cfg);
675
676         g_assert ((cfg->code - cfg->start) < cfg->code_size);
677 }
678
679 static void
680 mono_emit_cfg (MonoFlowGraph *cfg)
681 {
682         int i, j;
683
684         for (i = 0; i < cfg->block_count; i++) {
685                 MonoBBlock *bb = &cfg->bblocks [i];
686                 GPtrArray *forest = bb->forest;
687                 const int top = forest->len;
688
689                 bb->addr = cfg->code - cfg->start;
690           
691                 for (j = 0; j < top; j++) {
692                         MBTree *t1 = (MBTree *) g_ptr_array_index (forest, j);
693                         
694                         tree_emit (1, cfg, t1);
695                 }
696         }
697                 
698         cfg->epilog = cfg->code - cfg->start;
699 }
700
701 static void
702 mono_compute_branches (MonoFlowGraph *cfg)
703 {
704         guint8 *end;
705         int i, j;
706
707         end = cfg->code;
708
709         for (j = 0; j < cfg->block_count; j++) {
710                 MonoBBlock *bb = &cfg->bblocks [j];
711                 GPtrArray *forest = bb->forest;
712                 const int top = forest->len;
713         
714                 for (i = 0; i < top; i++) {
715                         MBTree *t1 = (MBTree *) g_ptr_array_index (forest, i);
716
717                         if (t1->is_jump) {
718
719                                 if (t1->op == MB_TERM_SWITCH) {
720                                         MonoBBlock **jt = (MonoBBlock **)t1->data.p;
721                                         guint32 *rt = (guint32 *)t1->data.p;
722
723                                         int m = *((guint32 *)t1->data.p) + 1;
724                                         int j;
725                                         
726                                         for (j = 1; j <= m; j++)
727                                                 rt [j] = (int)(jt [j]->addr + cfg->start);
728                                 }
729
730                                 /* emit the jump instruction again to update addresses */
731                                 cfg->code = cfg->start + t1->addr;
732                                 ((MBEmitFunc)t1->emit) (t1, cfg);
733
734                         }
735                 }
736         }
737
738         cfg->code = end;
739 }
740
741 static int
742 match_debug_method (MonoMethod* method)
743 {
744         GList *tmp = mono_debug_methods;
745
746         for (; tmp; tmp = tmp->next) {
747                 if (strcmp (method->name, tmp->data) == 0) {
748                         return 1;
749                 }
750         }
751         return 0;
752 }
753
754 /**
755  * arch_compile_method:
756  * @method: pointer to the method info
757  *
758  * JIT compilation of a single method. This method also writes the result 
759  * back to method->addr, an thus overwrites the trampoline function.
760  *
761  * Returns: a pointer to the newly created code.
762  */
763 gpointer
764 arch_compile_method (MonoMethod *method)
765 {
766         MonoFlowGraph *cfg;
767         MonoMemPool *mp = mono_mempool_new ();
768
769         g_assert (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL));
770         g_assert (!(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL));
771
772         if (mono_jit_trace_calls || mono_jit_dump_asm || mono_jit_dump_forest) {
773                 printf ("Start JIT compilation of %s.%s:%s\n", method->klass->name_space,
774                         method->klass->name, method->name);
775         }
776
777         if (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
778                 MonoClassField *field;
779                 const char *name = method->name;
780                 static guint target_offset = 0;
781                 static guint method_offset = 0;
782                 guint8 *code;
783                 gboolean delegate = FALSE;
784
785                 if (method->klass->parent && 
786                     method->klass->parent->parent == mono_defaults.delegate_class)
787                         delegate = TRUE;
788                                 
789                 if (!target_offset) {
790                         mono_class_init (mono_defaults.delegate_class);
791
792                         field = mono_class_get_field_from_name (mono_defaults.delegate_class, "m_target");
793                         target_offset = field->offset;
794                         field = mono_class_get_field_from_name (mono_defaults.delegate_class, "method_ptr");
795                         method_offset = field->offset;
796                 }
797                 
798                 if (delegate && *name == '.' && (strcmp (name, ".ctor") == 0)) {
799                         method->addr = code = g_malloc (32);
800                         x86_push_reg (code, X86_EBP);
801                         x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
802                         
803                         /* load the this pointer */
804                         x86_mov_reg_membase (code, X86_EAX, X86_EBP, 8, 4); 
805                         /* load m_target arg */
806                         x86_mov_reg_membase (code, X86_EDX, X86_EBP, 12, 4);
807                         /* store mtarget */
808                         x86_mov_membase_reg (code, X86_EAX, target_offset, X86_EDX, 4); 
809                         /* load method_ptr arg */
810                         x86_mov_reg_membase (code, X86_EDX, X86_EBP, 16, 4);
811                         /* store method_ptr */
812                         x86_mov_membase_reg (code, X86_EAX, method_offset, X86_EDX, 4); 
813
814                         x86_leave (code);
815                         x86_ret (code);
816
817                         g_assert ((code - (guint8*)method->addr) < 32);
818
819                 } else if (delegate && *name == 'I' && (strcmp (name, "Invoke") == 0)) {
820                         MonoMethodSignature *csig = method->signature;
821                         int i, target, this_pos = 4;
822                         guint8 *source;
823
824                         method->addr = g_malloc (32);
825
826                         if (csig->ret->type == MONO_TYPE_VALUETYPE) {
827                                 g_assert (!csig->ret->byref);
828                                 this_pos = 8;
829                         }
830
831                         for (i = 0; i < 2; i ++) {
832                                 code = method->addr;
833                                 /* load the this pointer */
834                                 x86_mov_reg_membase (code, X86_EAX, X86_ESP, this_pos, 4);
835                                 /* load mtarget */
836                                 x86_mov_reg_membase (code, X86_EDX, X86_EAX, target_offset, 4); 
837                                 /* check if zero (static method call without this pointer) */
838                                 x86_alu_reg_imm (code, X86_CMP, X86_EDX, 0);
839                                 x86_branch32 (code, X86_CC_EQ, target, TRUE); 
840                                 source = code;
841                                 
842                                 /* virtual call -  we have to replace the this pointer */
843                                 x86_mov_membase_reg (code, X86_ESP, this_pos, X86_EDX, 4); 
844
845                                 /* jump to method_ptr() */
846                                 target = code - source;
847                                 x86_jump_membase (code, X86_EAX, method_offset);
848                         }
849
850                         g_assert ((code - (guint8*)method->addr) < 32);
851
852                 } else {
853                         if (mono_debug_handle)
854                                 return NULL;
855                         g_error ("Don't know how to exec runtime method %s.%s::%s", 
856                                  method->klass->name_space, method->klass->name, method->name);
857                 }
858         
859         } else {
860                 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
861                 MonoJitInfo *ji = g_new0 (MonoJitInfo, 1);
862                 
863                 cfg = mono_cfg_new (method, mp);
864
865                 mono_analyze_flow (cfg);
866                 if (cfg->invalid)
867                         return NULL;
868
869                 mono_analyze_stack (cfg);
870                 if (cfg->invalid)
871                         return NULL;
872         
873                 cfg->rs = mono_regset_new (X86_NREG);
874                 mono_regset_reserve_reg (cfg->rs, X86_ESP);
875                 mono_regset_reserve_reg (cfg->rs, X86_EBP);
876
877                 cfg->code_size = 256;
878                 cfg->start = cfg->code = g_malloc (cfg->code_size);
879
880                 if (match_debug_method (method))
881                         x86_breakpoint (cfg->code);
882
883                 if (mono_jit_dump_forest) {
884                         int i;
885                         printf ("FOREST %s.%s:%s\n", method->klass->name_space,
886                                 method->klass->name, method->name);
887                         for (i = 0; i < cfg->block_count; i++) {
888                                 printf ("BLOCK %d:\n", i);
889                                 mono_print_forest (cfg->bblocks [i].forest);
890                         }
891                 }
892         
893                 mono_label_cfg (cfg);
894                 if (cfg->invalid)
895                         return NULL;
896
897                 arch_allocate_regs (cfg);
898
899                 /* align to 8 byte boundary */
900                 cfg->locals_size += 7;
901                 cfg->locals_size &= ~7;
902
903                 arch_emit_prologue (cfg);
904                 mono_emit_cfg (cfg);
905                 arch_emit_epilogue (cfg);               
906
907                 method->addr = cfg->start;
908
909                 mono_compute_branches (cfg);
910                 
911                 if (mono_jit_dump_asm) {
912                         char *id = g_strdup_printf ("%s_%s__%s", method->klass->name_space,
913                                                     method->klass->name, method->name);
914                         mono_disassemble_code (cfg->start, cfg->code - cfg->start, id);
915                         g_free (id);
916                 }
917                 if (mono_debug_handle)
918                         mono_debug_add_method (mono_debug_handle, cfg);
919
920                 ji->code_size = cfg->code - cfg->start;
921                 ji->used_regs = cfg->rs->used_mask;
922                 ji->method = method;
923                 ji->code_start = method->addr;
924                 mono_jit_info_table_add (mono_jit_info_table, ji);
925
926                 if (header->num_clauses) {
927                         int i, start_block, end_block;
928
929                         ji->num_clauses = header->num_clauses;
930                         ji->clauses = g_new0 (MonoJitExceptionInfo, header->num_clauses);
931
932                         for (i = 0; i < header->num_clauses; i++) {
933                                 MonoExceptionClause *ec = &header->clauses [i];
934                                 MonoJitExceptionInfo *ei = &ji->clauses [i];
935                         
936                                 ei->flags = ec->flags;
937                                 ei->token_or_filter = ec->token_or_filter;
938
939                                 g_assert (cfg->bcinfo [ec->try_offset].is_block_start);
940                                 start_block = cfg->bcinfo [ec->try_offset].block_id;
941                                 end_block = cfg->bcinfo [ec->try_offset + ec->try_len].block_id;
942                                 g_assert (cfg->bcinfo [ec->try_offset + ec->try_len].is_block_start);
943                                 
944                                 ei->try_start = cfg->start + cfg->bblocks [start_block].addr;
945                                 ei->try_end = cfg->start + cfg->bblocks [end_block].addr;
946                                 
947                                 g_assert (cfg->bcinfo [ec->handler_offset].is_block_start);
948                                 start_block = cfg->bcinfo [ec->handler_offset].block_id;
949                                 ei->handler_start = cfg->start + cfg->bblocks [start_block].addr;       
950                                 
951                                 //printf ("TEST %x %x %x\n", ei->try_start, ei->try_end, ei->handler_start);
952                         }
953                 }
954                 
955                 mono_regset_free (cfg->rs);
956
957                 mono_cfg_free (cfg);
958
959                 mono_mempool_destroy (mp);
960
961         }
962
963         if (mono_jit_trace_calls || mono_jit_dump_asm || mono_jit_dump_forest) {
964                 printf ("END JIT compilation of %s.%s:%s %p %p\n", method->klass->name_space,
965                         method->klass->name, method->name, method, method->addr);
966         }
967
968
969         return method->addr;
970 }
971
972 /*
973  * arch_get_restore_context:
974  *
975  * Returns a pointer to a method which restores a previously saved sigcontext.
976  */
977 static gpointer
978 arch_get_restore_context ()
979 {
980         static guint8 *start = NULL;
981         guint8 *code;
982
983         if (start)
984                 return start;
985
986         /* restore_contect (struct sigcontext *ctx) */
987         /* we do not restore X86_EAX, X86_EDX */
988
989         start = code = malloc (1024);
990         
991         /* load ctx */
992         x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
993
994         /* get return address, stored in EDX */
995         x86_mov_reg_membase (code, X86_EDX, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, eip), 4);
996
997         /* restore EBX */
998         x86_mov_reg_membase (code, X86_EBX, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, ebx), 4);
999         /* restore EDI */
1000         x86_mov_reg_membase (code, X86_EDI, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, edi), 4);
1001         /* restore ESI */
1002         x86_mov_reg_membase (code, X86_ESI, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, esi), 4);
1003         /* restore ESP */
1004         x86_mov_reg_membase (code, X86_ESP, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, esp), 4);
1005         /* restore EBP */
1006         x86_mov_reg_membase (code, X86_EBP, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, ebp), 4);
1007         /* restore ECX. the exception object is passed here to the catch handler */
1008         x86_mov_reg_membase (code, X86_ECX, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, ecx), 4);
1009
1010         /* jump to the saved IP */
1011         x86_jump_reg (code, X86_EDX);
1012
1013         return start;
1014 }
1015
1016 /*
1017  * arch_get_call_finally:
1018  *
1019  * Returns a pointer to a method which calls a finally handler.
1020  */
1021 static gpointer
1022 arch_get_call_finally ()
1023 {
1024         static guint8 *start = NULL;
1025         guint8 *code;
1026
1027         if (start)
1028                 return start;
1029
1030         /* call_finally (struct sigcontext *ctx, unsigned long eip) */
1031         start = code = malloc (1024);
1032
1033         x86_push_reg (code, X86_EBP);
1034         x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
1035         x86_push_reg (code, X86_EBX);
1036         x86_push_reg (code, X86_EDI);
1037         x86_push_reg (code, X86_ESI);
1038
1039         /* load ctx */
1040         x86_mov_reg_membase (code, X86_EAX, X86_EBP, 8, 4);
1041         /* load eip */
1042         x86_mov_reg_membase (code, X86_ECX, X86_EBP, 12, 4);
1043         /* save EBP */
1044         x86_push_reg (code, X86_EBP);
1045         /* set new EBP */
1046         x86_mov_reg_membase (code, X86_EBP, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, ebp), 4);
1047         /* call the handler */
1048         x86_call_reg (code, X86_ECX);
1049         /* restore EBP */
1050         x86_pop_reg (code, X86_EBP);
1051         /* restore saved regs */
1052         x86_pop_reg (code, X86_ESI);
1053         x86_pop_reg (code, X86_EDI);
1054         x86_pop_reg (code, X86_EBX);
1055         x86_leave (code);
1056         x86_ret (code);
1057
1058         return start;
1059 }
1060
1061 /**
1062  * arch_handle_exception:
1063  * @ctx: saved processor state
1064  * @obj:
1065  */
1066 void
1067 arch_handle_exception (struct sigcontext *ctx, gpointer obj)
1068 {
1069         MonoJitInfo *ji;
1070         gpointer ip = (gpointer)ctx->eip;
1071         static void (*restore_context) (struct sigcontext *);
1072         static void (*call_finally) (struct sigcontext *, unsigned long);
1073
1074         ji = mono_jit_info_table_find (mono_jit_info_table, ip);
1075
1076         if (!restore_context)
1077                 restore_context = arch_get_restore_context ();
1078         
1079         if (!call_finally)
1080                 call_finally = arch_get_call_finally ();
1081
1082         if (ji) { /* we are inside managed code */
1083                 MonoMethod *m = ji->method;
1084                 unsigned next_bp, next_ip;
1085                 int offset = 2;
1086
1087                 if (ji->num_clauses) {
1088                         int i;
1089
1090                         g_assert (ji->clauses);
1091                         
1092                         for (i = 0; i < ji->num_clauses; i++) {
1093                                 MonoJitExceptionInfo *ei = &ji->clauses [i];
1094
1095                                 if (ei->try_start <= ip && ip <= (ei->try_end)) { 
1096                                         /* catch block */
1097                                         if (ei->flags == 0 && mono_object_isinst (obj, 
1098                                                 mono_class_get (m->klass->image, ei->token_or_filter))) {
1099                                         
1100                                                 ctx->eip = (unsigned long)ei->handler_start;
1101                                                 ctx->ecx = (unsigned long)obj;
1102                                                 restore_context (ctx);
1103                                                 g_assert_not_reached ();
1104                                         }
1105                                 }
1106                         }
1107
1108                         /* no handler found - we need to call all finally handlers */
1109                         for (i = 0; i < ji->num_clauses; i++) {
1110                                 MonoJitExceptionInfo *ei = &ji->clauses [i];
1111
1112                                 if (ei->try_start <= ip && ip < (ei->try_end) &&
1113                                     (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
1114                                         call_finally (ctx, (unsigned long)ei->handler_start);
1115                                 }
1116                         }
1117                 }
1118
1119                 /* continue unwinding */
1120
1121                 /* restore caller saved registers */
1122                 if (ji->used_regs & X86_ESI_MASK) {
1123                         ctx->esi = *((int *)ctx->ebp + offset);
1124                         offset++;
1125                 }
1126                 if (ji->used_regs & X86_EDI_MASK) {
1127                         ctx->edi = *((int *)ctx->ebp + offset);
1128                         offset++;
1129                 }
1130                 if (ji->used_regs & X86_EBX_MASK) {
1131                         ctx->ebx = *((int *)ctx->ebp + offset);
1132                 }
1133
1134                 ctx->esp = ctx->ebp;
1135                 ctx->eip = *((int *)ctx->ebp + 1);
1136                 ctx->ebp = *((int *)ctx->ebp);
1137                 
1138                 if (next_bp < (unsigned)mono_end_of_stack)
1139                         arch_handle_exception (ctx, obj);
1140                 else
1141                         mono_jit_abort (obj);
1142
1143         } else {
1144                 gpointer *lmf_addr = TlsGetValue (lmf_thread_id);
1145                 MonoLMF *lmf;
1146                 MonoMethod *m;
1147
1148                 g_assert (lmf_addr);
1149                 lmf = *((MonoLMF **)lmf_addr);
1150
1151                 if (!lmf)
1152                         mono_jit_abort (obj);
1153
1154                 m = lmf->method;
1155
1156                 *lmf_addr = lmf->previous_lmf;
1157
1158                 ctx->esi = lmf->esi;
1159                 ctx->edi = lmf->edi;
1160                 ctx->ebx = lmf->ebx;
1161                 ctx->ebp = lmf->ebp;
1162                 ctx->eip = lmf->eip;
1163                 ctx->esp = lmf;
1164
1165                 /*
1166                 g_warning ("Exception inside unmanaged code. %s.%s::%s %p", m->klass->name_space,
1167                            m->klass->name, m->name, lmf->previous_lmf);
1168                 */
1169
1170                 if (ctx->eip < (unsigned)mono_end_of_stack)
1171                         arch_handle_exception (ctx, obj);
1172                 else
1173                         mono_jit_abort (obj);
1174         }
1175
1176         g_assert_not_reached ();
1177 }
1178
1179 static void
1180 throw_exception (unsigned long eax, unsigned long ecx, unsigned long edx, unsigned long ebx,
1181                  unsigned long esi, unsigned long edi, unsigned long ebp, MonoObject *exc,
1182                  unsigned long eip,  unsigned long esp)
1183 {
1184         struct sigcontext ctx;
1185         
1186         ctx.esp = esp;
1187         ctx.eip = eip;
1188         ctx.ebp = ebp;
1189         ctx.edi = edi;
1190         ctx.esi = esi;
1191         ctx.ebx = ebx;
1192         ctx.edx = edx;
1193         ctx.ecx = ecx;
1194         ctx.eax = eax;
1195         
1196         arch_handle_exception (&ctx, exc);
1197
1198         g_assert_not_reached ();
1199 }
1200
1201 gpointer 
1202 arch_get_throw_exception (void)
1203 {
1204         static guint8 *start = NULL;
1205         guint8 *code;
1206
1207         if (start)
1208                 return start;
1209
1210         code = start = g_malloc (1024);
1211
1212         x86_push_reg (code, X86_ESP);
1213         x86_push_membase (code, X86_ESP, 4); /* IP */
1214         x86_push_membase (code, X86_ESP, 12); /* exception */
1215         x86_push_reg (code, X86_EBP);
1216         x86_push_reg (code, X86_EDI);
1217         x86_push_reg (code, X86_ESI);
1218         x86_push_reg (code, X86_EBX);
1219         x86_push_reg (code, X86_EDX);
1220         x86_push_reg (code, X86_ECX);
1221         x86_push_reg (code, X86_EAX);
1222         x86_call_code (code, throw_exception);
1223         /* we should never reach this breakpoint */
1224         x86_breakpoint (code);
1225
1226         return start;
1227 }
1228
1229
1230
1231