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