2002-04-20 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/debug-helpers.h>
20 #include <mono/metadata/mono-endian.h>
21 #include <mono/arch/x86/x86-codegen.h>
22 #include <mono/metadata/profiler-private.h>
23
24 #include "jit.h"
25 #include "codegen.h"
26 #include "debug.h"
27
28 static void
29 enter_method (MonoMethod *method, char *ebp)
30 {
31         int i, j;
32         MonoClass *class;
33         MonoObject *o;
34
35         printf ("ENTER: %s.%s::%s\n(", method->klass->name_space,
36                 method->klass->name, method->name);
37
38         
39         if (((int)ebp & 3) != 0) {
40                 g_error ("unaligned stack detected (%p)", ebp);
41         }
42
43         ebp += 8;
44
45         if (ISSTRUCT (method->signature->ret)) {
46                 int size, align;
47                 
48                 g_assert (!method->signature->ret->byref);
49
50                 size = mono_type_stack_size (method->signature->ret, &align);
51
52                 printf ("VALUERET:%p, ", *((gpointer *)ebp));
53                 ebp += sizeof (gpointer);
54         }
55
56         if (method->signature->hasthis) {
57                 if (method->klass->valuetype) {
58                         printf ("value:%p, ", *((gpointer *)ebp));
59                 } else {
60                         o = *((MonoObject **)ebp);
61
62                         g_assert (o);
63
64                         class = o->vtable->klass;
65
66                         if (class == mono_defaults.string_class) {
67                                 printf ("this:[STRING:%p:%s], ", o, mono_string_to_utf8 ((MonoString *)o));
68                         } else {
69                                 printf ("this:%p[%s.%s], ", o, class->name_space, class->name);
70                         }
71                 }
72                 ebp += sizeof (gpointer);
73         }
74
75         for (i = 0; i < method->signature->param_count; ++i) {
76                 MonoType *type = method->signature->params [i];
77                 int size, align;
78                 size = mono_type_stack_size (type, &align);
79
80                 if (type->byref) {
81                         printf ("[BYREF:%p], ", *((gpointer *)ebp)); 
82                 } else switch (type->type) {
83                         
84                 case MONO_TYPE_BOOLEAN:
85                 case MONO_TYPE_CHAR:
86                 case MONO_TYPE_I1:
87                 case MONO_TYPE_U1:
88                 case MONO_TYPE_I2:
89                 case MONO_TYPE_U2:
90                 case MONO_TYPE_I4:
91                 case MONO_TYPE_U4:
92                 case MONO_TYPE_I:
93                 case MONO_TYPE_U:
94                         printf ("%d, ", *((int *)(ebp)));
95                         break;
96                 case MONO_TYPE_STRING: {
97                         MonoString *s = *((MonoString **)ebp);
98                         if (s) {
99                                 g_assert (((MonoObject *)s)->vtable->klass == mono_defaults.string_class);
100                                 printf ("[STRING:%p:%s], ", s, mono_string_to_utf8 (s));
101                         } else 
102                                 printf ("[STRING:null], ");
103                         break;
104                 }
105                 case MONO_TYPE_CLASS:
106                 case MONO_TYPE_OBJECT: {
107                         o = *((MonoObject **)ebp);
108                         if (o) {
109                                 class = o->vtable->klass;
110                     
111                                 if (class == mono_defaults.string_class) {
112                                         printf ("[STRING:%p:%s], ", o, mono_string_to_utf8 ((MonoString *)o));
113                                 } else if (class == mono_defaults.int32_class) {
114                                         printf ("[INT32:%p:%d], ", o, *(gint32 *)((char *)o + sizeof (MonoObject)));
115                                 } else
116                                         printf ("[%s.%s:%p], ", class->name_space, class->name, o);
117                         } else {
118                                 printf ("%p, ", *((gpointer *)(ebp)));                          
119                         }
120                         break;
121                 }
122                 case MONO_TYPE_PTR:
123                 case MONO_TYPE_FNPTR:
124                 case MONO_TYPE_ARRAY:
125                 case MONO_TYPE_SZARRAY:
126                         printf ("%p, ", *((gpointer *)(ebp)));
127                         break;
128                 case MONO_TYPE_I8:
129                         printf ("%lld, ", *((gint64 *)(ebp)));
130                         break;
131                 case MONO_TYPE_R4:
132                         printf ("%f, ", *((float *)(ebp)));
133                         break;
134                 case MONO_TYPE_R8:
135                         printf ("%f, ", *((double *)(ebp)));
136                         break;
137                 case MONO_TYPE_VALUETYPE: 
138                         printf ("[");
139                         for (j = 0; j < size; j++)
140                                 printf ("%02x,", *((guint8*)ebp +j));
141                         printf ("], ");
142                         break;
143                 default:
144                         printf ("XX, ");
145                 }
146
147                 g_assert (align == 4);
148                 ebp += size + 3;
149                 ebp = (gpointer)((unsigned)ebp & ~(3));
150         }
151
152         printf (")\n");
153 }
154
155 static void
156 leave_method (MonoMethod *method, int edx, int eax, double test)
157 {
158         gint64 l;
159
160         printf ("LEAVE: %s.%s::%s ", method->klass->name_space,
161                 method->klass->name, method->name);
162
163         switch (method->signature->ret->type) {
164         case MONO_TYPE_VOID:
165                 break;
166         case MONO_TYPE_BOOLEAN:
167                 if (eax)
168                         printf ("TRUE:%d", eax);
169                 else 
170                         printf ("FALSE");
171                         
172                 break;
173         case MONO_TYPE_CHAR:
174         case MONO_TYPE_I1:
175         case MONO_TYPE_U1:
176         case MONO_TYPE_I2:
177         case MONO_TYPE_U2:
178         case MONO_TYPE_I4:
179         case MONO_TYPE_U4:
180         case MONO_TYPE_I:
181         case MONO_TYPE_U:
182                 printf ("EAX=%d", eax);
183                 break;
184         case MONO_TYPE_STRING: {
185                 MonoString *s = (MonoString *)eax;
186
187                 if (s) {
188                         g_assert (((MonoObject *)s)->vtable->klass == mono_defaults.string_class);
189                         printf ("[STRING:%p:%s]", s, mono_string_to_utf8 (s));
190                 } else 
191                         printf ("[STRING:null], ");
192                 break;
193         }
194         case MONO_TYPE_OBJECT: {
195                 MonoObject *o = (MonoObject *)eax;
196
197                 if (o) {
198                         if (o->vtable->klass == mono_defaults.boolean_class) {
199                                 printf ("[BOOLEAN:%p:%d]", o, *((guint8 *)o + sizeof (MonoObject)));            
200                         } else if  (o->vtable->klass == mono_defaults.int32_class) {
201                                 printf ("[INT32:%p:%d]", o, *((gint32 *)((char *)o + sizeof (MonoObject))));    
202                         } else
203                                 printf ("[%s.%s:%p]", o->vtable->klass->name_space, o->vtable->klass->name, o);
204                 } else
205                         printf ("[OBJECT:%p]", o);
206                
207                 break;
208         }
209         case MONO_TYPE_CLASS:
210         case MONO_TYPE_PTR:
211         case MONO_TYPE_FNPTR:
212         case MONO_TYPE_ARRAY:
213         case MONO_TYPE_SZARRAY:
214                 printf ("EAX=%p", (gpointer)eax);
215                 break;
216         case MONO_TYPE_I8:
217                 *((gint32 *)&l) = eax;
218                 *((gint32 *)&l + 1) = edx;
219                 printf ("EAX/EDX=%lld", l);
220                 break;
221         case MONO_TYPE_R8:
222                 printf ("FP=%f\n", test);
223                 break;
224         default:
225                 printf ("(unknown return type)");
226         }
227
228         printf ("\n");
229 }
230
231 /**
232  * arch_emit_prologue:
233  * @cfg: pointer to status information
234  *
235  * Emits the function prolog.
236  */
237 static void
238 arch_emit_prologue (MonoFlowGraph *cfg)
239 {
240         MonoMethod *method = cfg->method;
241         MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
242         int i, j;
243
244         x86_push_reg (cfg->code, X86_EBP);
245         x86_mov_reg_reg (cfg->code, X86_EBP, X86_ESP, 4);
246
247         if (cfg->locals_size)
248                 x86_alu_reg_imm (cfg->code, X86_SUB, X86_ESP, cfg->locals_size);
249
250         if (mono_regset_reg_used (cfg->rs, X86_EBX)) 
251                 x86_push_reg (cfg->code, X86_EBX);
252
253         if (mono_regset_reg_used (cfg->rs, X86_EDI)) 
254                 x86_push_reg (cfg->code, X86_EDI);
255
256         if (mono_regset_reg_used (cfg->rs, X86_ESI))
257                 x86_push_reg (cfg->code, X86_ESI);
258
259         if (mono_jit_trace_calls) {
260                 x86_push_reg (cfg->code, X86_EBP);
261                 x86_push_imm (cfg->code, cfg->method);
262                 x86_mov_reg_imm (cfg->code, X86_EAX, enter_method);
263                 x86_call_reg (cfg->code, X86_EAX);
264                 x86_alu_reg_imm (cfg->code, X86_ADD, X86_ESP, 8);
265         }
266         if (mono_jit_profile) {
267                 x86_push_imm (cfg->code, cfg->method);
268                 x86_mov_reg_imm (cfg->code, X86_EAX, mono_profiler_method_enter);
269                 x86_call_reg (cfg->code, X86_EAX);
270                 x86_alu_reg_imm (cfg->code, X86_ADD, X86_ESP, 4);
271         }
272
273         /* initialize local vars */
274         if (header->num_locals) {
275
276                 if (header->init_locals) {
277                         int offset = g_array_index (cfg->varinfo, MonoVarInfo, 
278                                                     cfg->locals_start_index + header->num_locals - 1).offset;  
279                         int size = - offset;
280
281                         if (size == 1 || size == 2 || size == 4) {
282                                 x86_mov_membase_imm (cfg->code, X86_EBP, offset, 0, size);
283                                 return;
284                         }
285                         
286                         i = size / 4;
287                         j = size % 4;
288         
289                         if (i) {
290                                 if (!mono_regset_reg_used (cfg->rs, X86_EDI)) 
291                                         x86_push_reg (cfg->code, X86_EDI);
292                                 x86_lea_membase (cfg->code, X86_EDI, X86_EBP, offset);
293                                 x86_alu_reg_reg (cfg->code, X86_XOR, X86_EAX, X86_EAX);
294                                 x86_mov_reg_imm (cfg->code, X86_ECX, i);
295                                 x86_cld (cfg->code);
296                                 x86_prefix (cfg->code, X86_REP_PREFIX);
297                                 x86_stosl (cfg->code);
298                                 for (i = 0; i < j; i++)
299                                         x86_stosb (cfg->code);
300                                 if (!mono_regset_reg_used (cfg->rs, X86_EDI)) 
301                                         x86_pop_reg (cfg->code, X86_EDI);
302                         } else {
303
304                                 g_assert (j == 3);
305                                 x86_mov_membase_imm (cfg->code, X86_EBP, offset, 0, 2);
306                                 x86_mov_membase_imm (cfg->code, X86_EBP, offset + 2, 0, 1);
307                         }
308                         
309                 } else {
310
311                         /* we always need to initialize object pointers */
312
313                         for (i = 0; i < header->num_locals; ++i) {
314                                 MonoType *t = header->locals [i];
315                                 int offset = g_array_index (cfg->varinfo, MonoVarInfo, cfg->locals_start_index + i).offset;  
316
317                                 if (t->byref) {
318                                         x86_mov_membase_imm (cfg->code, X86_EBP, offset, 0, 4);
319                                         continue;
320                                 }
321
322                                 switch (t->type) {
323                                 case MONO_TYPE_STRING:
324                                 case MONO_TYPE_CLASS:
325                                 case MONO_TYPE_ARRAY:
326                                 case MONO_TYPE_SZARRAY:
327                                 case MONO_TYPE_OBJECT:
328                                         x86_mov_membase_imm (cfg->code, X86_EBP, offset, 0, 4);
329                                         break;
330                                 }
331
332                         }
333                 }
334         }
335 }
336
337 /**
338  * arch_emit_epilogue:
339  * @cfg: pointer to status information
340  *
341  * Emits the function epilog.
342  */
343 static void
344 arch_emit_epilogue (MonoFlowGraph *cfg)
345 {
346         /*
347          * note: with trace and profiling the value on the FP stack may get clobbered.
348          */
349         if (mono_jit_trace_calls) {
350                 x86_fld_reg (cfg->code, 0);
351                 x86_alu_reg_imm (cfg->code, X86_SUB, X86_ESP, 8);
352                 x86_fst_membase (cfg->code, X86_ESP, 0, TRUE, TRUE);
353                 x86_push_reg (cfg->code, X86_EAX);
354                 x86_push_reg (cfg->code, X86_EDX);
355                 x86_push_imm (cfg->code, cfg->method);
356                 x86_mov_reg_imm (cfg->code, X86_EAX, leave_method);
357                 x86_call_reg (cfg->code, X86_EAX);
358                 x86_alu_reg_imm (cfg->code, X86_ADD, X86_ESP, 4);
359                 x86_pop_reg (cfg->code, X86_EDX);
360                 x86_pop_reg (cfg->code, X86_EAX);
361                 x86_alu_reg_imm (cfg->code, X86_ADD, X86_ESP, 8);
362         }
363         if (mono_jit_profile) {
364                 x86_push_reg (cfg->code, X86_EAX);
365                 x86_push_reg (cfg->code, X86_EDX);
366                 x86_push_imm (cfg->code, cfg->method);
367                 x86_mov_reg_imm (cfg->code, X86_EAX, mono_profiler_method_leave);
368                 x86_call_reg (cfg->code, X86_EAX);
369                 x86_alu_reg_imm (cfg->code, X86_ADD, X86_ESP, 4);
370                 x86_pop_reg (cfg->code, X86_EDX);
371                 x86_pop_reg (cfg->code, X86_EAX);
372         }
373
374         if (mono_regset_reg_used (cfg->rs, X86_ESI))
375                 x86_pop_reg (cfg->code, X86_ESI);
376
377         if (mono_regset_reg_used (cfg->rs, X86_EDI))
378                 x86_pop_reg (cfg->code, X86_EDI);
379
380         if (mono_regset_reg_used (cfg->rs, X86_EBX))
381                 x86_pop_reg (cfg->code, X86_EBX);
382
383         x86_leave (cfg->code);
384         x86_ret (cfg->code);
385 }
386
387 static void
388 mono_label_cfg (MonoFlowGraph *cfg)
389 {
390         int i, j;
391
392         for (i = 0; i < cfg->block_count; i++) {
393                 GPtrArray *forest = cfg->bblocks [i].forest;
394                 int top;
395
396                 if (!cfg->bblocks [i].reached) /* unreachable code */
397                         continue;
398                 
399                 top = forest->len;
400
401                 for (j = 0; j < top; j++) {
402                         MBTree *t1 = (MBTree *) g_ptr_array_index (forest, j);
403                         MBState *mbstate;
404
405                         mbstate =  mono_burg_label (t1, cfg);
406
407                         if (!mbstate) {
408                                 cfg->invalid = 1;
409                                 if (mono_debug_handle)
410                                         return;
411                                 g_warning ("tree does not match");
412                                 mono_print_ctree (t1); printf ("\n\n");
413
414                                 mono_print_forest (forest);
415                                 g_assert_not_reached ();
416                         }
417                 }
418         }
419 }
420
421 static void
422 tree_preallocate_regs (MBTree *tree, int goal, MonoRegSet *rs) 
423 {
424         switch (tree->op) {
425         case MB_TERM_CALL_I4:
426         case MB_TERM_CALL_I8:
427         case MB_TERM_CALL_R8:
428 //      case MB_TERM_CALL_VOID :
429                 tree->reg1 = mono_regset_alloc_reg (rs, X86_EAX, tree->exclude_mask);
430                 tree->reg2 = mono_regset_alloc_reg (rs, X86_EDX, tree->exclude_mask);
431                 tree->reg3 = mono_regset_alloc_reg (rs, X86_ECX, tree->exclude_mask);
432                 return;
433         default: break;
434         }
435
436         switch (goal) {
437         case MB_NTERM_reg:
438         case MB_NTERM_lreg: {
439                 switch (tree->op) {
440                 case MB_TERM_SHL:
441                 case MB_TERM_SHR:
442                 case MB_TERM_SHR_UN:
443                         tree->exclude_mask |= (1 << X86_ECX);
444                         tree->left->exclude_mask |= (1 << X86_ECX);
445                         break;
446                 case MB_TERM_MUL:
447                 case MB_TERM_MUL_OVF:
448                 case MB_TERM_MUL_OVF_UN:
449                 case MB_TERM_DIV:
450                 case MB_TERM_DIV_UN:
451                 case MB_TERM_REM:
452                 case MB_TERM_REM_UN:
453                         tree->reg1 = mono_regset_alloc_reg (rs, X86_EAX, tree->exclude_mask);
454                         tree->reg2 = mono_regset_alloc_reg (rs, X86_EDX, tree->exclude_mask);
455                         if (goal == MB_NTERM_reg) {
456                                 tree->left->exclude_mask |= (1 << X86_EDX);
457                                 tree->right->exclude_mask |= (1 << X86_EDX) | (1 << X86_EAX);
458                         }
459                         break;
460                 default:
461                         break;
462                 }
463                 break;
464         }
465         default:
466                 break;
467         }
468 }
469
470 static void
471 tree_allocate_regs (MBTree *tree, int goal, MonoRegSet *rs) 
472 {
473         MBTree *kids[10];
474         int ern = mono_burg_rule (tree->state, goal);
475         const guint16 *nts = mono_burg_nts [ern];
476         int i;
477         
478         mono_burg_kids (tree, ern, kids);
479
480         //printf ("RALLOC START %d %p %d %d\n",  tree->op, rs->free_mask, goal, (nts [0] && kids [0] == tree));
481
482         if (nts [0] && kids [0] == tree) {
483                 /* chain rule */
484                 tree_allocate_regs (kids [0], nts [0], rs);
485                 /* special case reg: coni4 */
486                 if (goal == MB_NTERM_reg) {
487                         if (tree->reg1 == -1)
488                                 tree->reg1 = mono_regset_alloc_reg (rs, -1, tree->exclude_mask);
489                         g_assert (tree->reg1 != -1);
490                 }
491                 return;
492         }
493
494         for (i = 0; nts [i]; i++)
495                 tree_preallocate_regs (kids [i], nts [i], rs);
496
497         for (i = 0; nts [i]; i++)
498                 tree_allocate_regs (kids [i], nts [i], rs);
499
500         for (i = 0; nts [i]; i++) {
501                 mono_regset_free_reg (rs, kids [i]->reg1);
502                 mono_regset_free_reg (rs, kids [i]->reg2);
503                 mono_regset_free_reg (rs, kids [i]->reg3);
504         }
505
506         switch (goal) {
507         case MB_NTERM_reg:
508                 if (tree->reg1 < 0) { 
509                         tree->reg1 = mono_regset_alloc_reg (rs, -1, tree->exclude_mask);
510                         g_assert (tree->reg1 != -1);
511                 }
512                 break;
513
514         case MB_NTERM_lreg:
515                 if (tree->reg1 < 0) { 
516                         tree->reg1 = mono_regset_alloc_reg (rs, -1, tree->exclude_mask);
517                         g_assert (tree->reg1 != -1);
518                 }
519                 if (tree->reg2 < 0) { 
520                         tree->reg2 = mono_regset_alloc_reg (rs, -1, tree->exclude_mask);
521                         g_assert (tree->reg2 != -1);
522                 }
523                 break;
524
525         case MB_NTERM_freg:
526                 /* fixme: allocate floating point registers */
527                 break;
528       
529         case MB_NTERM_addr:
530                 if (tree->op == MB_TERM_ADD) {
531                         tree->reg1 = mono_regset_alloc_reg (rs, tree->left->reg1, tree->exclude_mask);
532                         tree->reg2 = mono_regset_alloc_reg (rs, tree->right->reg1, tree->exclude_mask);
533                 }
534                 break;
535                 
536         case MB_NTERM_base:
537                 if (tree->op == MB_TERM_ADD) {
538                         tree->reg1 = mono_regset_alloc_reg (rs, tree->left->reg1, tree->exclude_mask);
539                 }
540                 break;
541                
542         case MB_NTERM_index:
543                 if (tree->op == MB_TERM_SHL ||
544                     tree->op == MB_TERM_MUL) {
545                         tree->reg1 = mono_regset_alloc_reg (rs, tree->left->reg1, tree->exclude_mask);
546                 }
547                 break;
548                
549         default:
550                 /* do nothing */
551         }
552
553         //printf ("RALLOC END %d %p\n",  tree->op, rs->free_mask);
554         tree->emit = mono_burg_func [ern];
555 }
556
557 static void
558 arch_allocate_regs (MonoFlowGraph *cfg)
559 {
560         int i, j;
561         
562         for (i = 0; i < cfg->block_count; i++) {
563                 GPtrArray *forest = cfg->bblocks [i].forest;
564                 int top;
565
566                 if (!cfg->bblocks [i].reached) /* unreachable code */
567                         continue;
568
569                 top = forest->len;
570
571                 for (j = 0; j < top; j++) {
572                         MBTree *t1 = (MBTree *) g_ptr_array_index (forest, j);
573                         //printf ("AREGSTART %d:%d %p\n", i, j, cfg->rs->free_mask);
574                         tree_allocate_regs (t1, 1, cfg->rs);
575                         //printf ("AREGENDT %d:%d %p\n", i, j, cfg->rs->free_mask);
576                         g_assert (cfg->rs->free_mask == 0xffffffff);
577                 }
578         }
579 }
580
581 static void
582 tree_emit (int goal, MonoFlowGraph *cfg, MBTree *tree) 
583 {
584         MBTree *kids[10];
585         int i, ern = mono_burg_rule (tree->state, goal);
586         const guint16 *nts = mono_burg_nts [ern];
587         MBEmitFunc emit;
588         int offset;
589
590         mono_burg_kids (tree, ern, kids);
591
592         for (i = 0; nts [i]; i++) 
593                 tree_emit (nts [i], cfg, kids [i]);
594
595         tree->addr = offset = cfg->code - cfg->start;
596
597         // we assume an instruction uses a maximum of 128 bytes
598         if ((cfg->code_size - offset) <= 128) {
599                 int add = MIN (cfg->code_size, 128);
600                 cfg->code_size += add;
601                 mono_jit_stats.code_reallocs++;
602                 cfg->start = g_realloc (cfg->start, cfg->code_size);
603                 g_assert (cfg->start);
604                 cfg->code = cfg->start + offset;
605         }
606
607         if ((emit = mono_burg_func [ern]))
608                 emit (tree, cfg);
609
610         g_assert ((cfg->code - cfg->start) < cfg->code_size);
611 }
612
613 static void
614 mono_emit_cfg (MonoFlowGraph *cfg)
615 {
616         int i, j;
617
618         for (i = 0; i < cfg->block_count; i++) {
619                 MonoBBlock *bb = &cfg->bblocks [i];
620                 GPtrArray *forest = bb->forest;
621                 int top;
622
623                 if (!bb->reached) /* unreachable code */
624                         continue;
625                 
626                 top = forest->len;
627
628                 bb->addr = cfg->code - cfg->start;
629           
630                 for (j = 0; j < top; j++) {
631                         MBTree *t1 = (MBTree *) g_ptr_array_index (forest, j);
632                         
633                         tree_emit (1, cfg, t1);
634                 }
635         }
636                 
637         cfg->epilog = cfg->code - cfg->start;
638 }
639
640 static void
641 mono_compute_branches (MonoFlowGraph *cfg)
642 {
643         MonoJumpInfo *ji;
644         guint8 *end;
645         int i, j;
646
647         end = cfg->code;
648
649         for (j = 0; j < cfg->block_count; j++) {
650                 MonoBBlock *bb = &cfg->bblocks [j];
651                 GPtrArray *forest = bb->forest;
652                 int top;
653                 
654                 if (!bb->reached) /* unreachable code */
655                         continue;
656
657                 top = forest->len;
658         
659                 for (i = 0; i < top; i++) {
660                         MBTree *t1 = (MBTree *) g_ptr_array_index (forest, i);
661
662                         if (t1->op == MB_TERM_SWITCH) {
663                                 MonoBBlock **jt = (MonoBBlock **)t1->data.p;
664                                 guint32 *rt = (guint32 *)t1->data.p;
665                                 int m = *((guint32 *)t1->data.p) + 1;
666                                 int k;
667                                 
668                                 for (k = 1; k <= m; k++)
669                                         rt [k] = (int)(jt [k]->addr + cfg->start);
670                                 
671                                 /* emit the switch instruction again to update addresses */
672                                 cfg->code = cfg->start + t1->addr;
673                                 ((MBEmitFunc)t1->emit) (t1, cfg);
674                         }
675                 }
676         }
677
678         cfg->code = end;
679
680         for (ji = cfg->jump_info; ji; ji = ji->next) {
681                 gpointer *ip = GUINT_TO_POINTER (GPOINTER_TO_UINT (ji->ip) + cfg->start);
682                 char *target;
683
684                 switch (ji->type) {
685                 case MONO_JUMP_INFO_BB:
686                         target = ji->data.bb->addr + cfg->start;
687                         *ip = target - GPOINTER_TO_UINT(ip) - 4;
688                         break;
689                 case MONO_JUMP_INFO_ABS:
690                         target = ji->data.target;
691                         *ip = target - GPOINTER_TO_UINT(ip) - 4;
692                         break;
693                 case MONO_JUMP_INFO_EPILOG:
694                         target = cfg->epilog + cfg->start;
695                         *ip = target - GPOINTER_TO_UINT(ip) - 4;
696                         break;
697                 case MONO_JUMP_INFO_IP:
698                         *ip = ip;
699                         break;
700                 default:
701                         g_assert_not_reached ();
702                 }
703         }
704 }
705
706 void
707 mono_add_jump_info (MonoFlowGraph *cfg, gpointer ip, MonoJumpInfoType type, gpointer target)
708 {
709         MonoJumpInfo *ji = mono_mempool_alloc (cfg->mp, sizeof (MonoJumpInfo));
710
711         ji->type = type;
712         ji->ip = GUINT_TO_POINTER (GPOINTER_TO_UINT (ip) - GPOINTER_TO_UINT (cfg->start));
713         ji->data.target = target;
714         ji->next = cfg->jump_info;
715
716         cfg->jump_info = ji;
717 }
718
719 static int
720 match_debug_method (MonoMethod* method)
721 {
722         GList *tmp = mono_debug_methods;
723
724         for (; tmp; tmp = tmp->next) {
725                 if (mono_method_desc_full_match (tmp->data, method))
726                         return 1;
727         }
728         return 0;
729 }
730
731 /**
732  * arch_compile_method:
733  * @method: pointer to the method info
734  *
735  * JIT compilation of a single method. 
736  *
737  * Returns: a pointer to the newly created code.
738  */
739 gpointer
740 arch_compile_method (MonoMethod *method)
741 {
742         MonoDomain *target_domain, *domain = mono_domain_get ();
743         MonoJitInfo *ji;
744         guint8 *addr;
745         GHashTable *jit_code_hash;
746
747         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
748             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
749                 if (!method->info)
750                         method->info = arch_create_native_wrapper (method);
751                 return method->info;
752         }
753
754         if (mono_jit_share_code)
755                 target_domain = mono_root_domain;
756         else 
757                 target_domain = domain;
758
759         jit_code_hash = target_domain->jit_code_hash;
760
761         if ((addr = g_hash_table_lookup (jit_code_hash, method))) {
762                 mono_jit_stats.methods_lookups++;
763                 return addr;
764         }
765
766         mono_jit_stats.methods_compiled++;
767         
768         if (mono_jit_trace_calls || mono_jit_dump_asm || mono_jit_dump_forest) {
769                 printf ("Start JIT compilation of %s.%s:%s\n", method->klass->name_space,
770                         method->klass->name, method->name);
771         }
772
773         if (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
774                 const char *name = method->name;
775                 guint8 *code;
776                 gboolean delegate = FALSE;
777
778                 if (method->klass->parent == mono_defaults.multicastdelegate_class)
779                         delegate = TRUE;
780                                 
781                 if (delegate && *name == '.' && (strcmp (name, ".ctor") == 0)) {
782                         addr = (gpointer)mono_delegate_ctor;
783                 } else if (delegate && *name == 'I' && (strcmp (name, "Invoke") == 0)) {
784                         int size;
785
786                         addr = arch_get_delegate_invoke (method, &size);
787
788                         if (mono_jit_dump_asm) {
789                                 char *id = g_strdup_printf ("%s.%s_%s", method->klass->name_space,
790                                                             method->klass->name, method->name);
791                                 mono_disassemble_code (addr, size, id);
792                                 g_free (id);
793                         }
794                 } else if (delegate && *name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
795                         code = addr = g_malloc (32);
796                         x86_push_imm (code, method);
797                         x86_call_code (code, arch_begin_invoke);
798                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
799                         x86_ret (code);
800                         g_assert ((code - addr) <= 32);
801                 } else if (delegate && *name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
802                         /* this can raise exceptions, so we need a wrapper to save/restore LMF */
803                         method->addr = (gpointer)arch_end_invoke;
804                         addr = arch_create_native_wrapper (method);
805                 } else {
806                         mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
807                         if (mono_debug_handle) 
808                                 return NULL;
809
810                         g_error ("Don't know how to exec runtime method %s.%s::%s", 
811                                  method->klass->name_space, method->klass->name, method->name);
812                 }
813         
814         } else {
815                 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
816                 MonoFlowGraph *cfg;
817                 MonoMemPool *mp;
818                 gulong code_size_ratio;
819         
820                 mono_profiler_method_jit (method);
821         
822                 ji = mono_mempool_alloc0 (target_domain->mp, sizeof (MonoJitInfo));
823                 
824                 mp = mono_mempool_new ();
825
826                 cfg = mono_cfg_new (method, mp);
827
828                 mono_analyze_flow (cfg);
829                 if (cfg->invalid) {
830                         mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
831                         return NULL;
832                 }
833                 
834                 mono_analyze_stack (cfg);
835                 if (cfg->invalid) {
836                         mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
837                         return NULL;
838                 }
839                 
840                 cfg->rs = mono_regset_new (X86_NREG);
841                 mono_regset_reserve_reg (cfg->rs, X86_ESP);
842                 mono_regset_reserve_reg (cfg->rs, X86_EBP);
843
844                 cfg->code_size = MAX (header->code_size * 5, 256);
845                 cfg->start = cfg->code = g_malloc (cfg->code_size);
846
847                 mono_debug_last_breakpoint_address = cfg->code;
848
849                 if (match_debug_method (method) || mono_debug_insert_breakpoint)
850                         x86_breakpoint (cfg->code);
851                 else if (mono_debug_handle)
852                         x86_nop (cfg->code);
853
854                 if (mono_debug_insert_breakpoint > 0)
855                         mono_debug_insert_breakpoint--;
856
857                 if (mono_jit_dump_forest) {
858                         int i;
859                         printf ("FOREST %s.%s:%s\n", method->klass->name_space,
860                                 method->klass->name, method->name);
861                         for (i = 0; i < cfg->block_count; i++) {
862                                 printf ("BLOCK %d:\n", i);
863                                 mono_print_forest (cfg->bblocks [i].forest);
864                         }
865                 }
866         
867                 mono_label_cfg (cfg);
868                 if (cfg->invalid) {
869                         mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
870                         return NULL;
871                 }
872                 
873                 arch_allocate_regs (cfg);
874
875                 /* align to 8 byte boundary */
876                 cfg->locals_size += 7;
877                 cfg->locals_size &= ~7;
878
879                 arch_emit_prologue (cfg);
880                 cfg->prologue_end = cfg->code - cfg->start;
881                 mono_emit_cfg (cfg);
882                 cfg->epilogue_begin = cfg->code - cfg->start;
883                 arch_emit_epilogue (cfg);               
884
885                 addr = cfg->start;
886
887                 mono_jit_stats.allocated_code_size += cfg->code_size;
888
889                 code_size_ratio = cfg->code - cfg->start;
890                 if (code_size_ratio > mono_jit_stats.biggest_method_size) {
891                         mono_jit_stats.biggest_method_size = code_size_ratio;
892                         mono_jit_stats.biggest_method = method;
893                 }
894                 code_size_ratio = (code_size_ratio * 100) / header->code_size;
895                 if (code_size_ratio > mono_jit_stats.max_code_size_ratio) {
896                         mono_jit_stats.max_code_size_ratio = code_size_ratio;
897                         mono_jit_stats.max_ratio_method = method;
898                 }
899
900                 mono_compute_branches (cfg);
901                 
902                 if (mono_jit_dump_asm) {
903                         char *id = g_strdup_printf ("%s.%s_%s", method->klass->name_space,
904                                                     method->klass->name, method->name);
905                         mono_disassemble_code (cfg->start, cfg->code - cfg->start, id);
906                         g_free (id);
907                 }
908                 if (mono_debug_handle)
909                         mono_debug_add_method (mono_debug_handle, cfg);
910
911                 ji->code_size = cfg->code - cfg->start;
912                 ji->used_regs = cfg->rs->used_mask;
913                 ji->method = method;
914                 ji->code_start = addr;
915
916                 mono_jit_stats.native_code_size += ji->code_size;
917
918                 if (header->num_clauses) {
919                         int i, start_block, end_block;
920
921                         ji->num_clauses = header->num_clauses;
922                         ji->clauses = mono_mempool_alloc0 (target_domain->mp, 
923                                 sizeof (MonoJitExceptionInfo) * header->num_clauses);
924
925                         for (i = 0; i < header->num_clauses; i++) {
926                                 MonoExceptionClause *ec = &header->clauses [i];
927                                 MonoJitExceptionInfo *ei = &ji->clauses [i];
928                         
929                                 ei->flags = ec->flags;
930                                 ei->token_or_filter = ec->token_or_filter;
931
932                                 g_assert (cfg->bcinfo [ec->try_offset].is_block_start);
933                                 start_block = cfg->bcinfo [ec->try_offset].block_id;
934                                 end_block = cfg->bcinfo [ec->try_offset + ec->try_len].block_id;
935                                 g_assert (cfg->bcinfo [ec->try_offset + ec->try_len].is_block_start);
936                                 
937                                 ei->try_start = cfg->start + cfg->bblocks [start_block].addr;
938                                 ei->try_end = cfg->start + cfg->bblocks [end_block].addr;
939                                 
940                                 g_assert (cfg->bcinfo [ec->handler_offset].is_block_start);
941                                 start_block = cfg->bcinfo [ec->handler_offset].block_id;
942                                 ei->handler_start = cfg->start + cfg->bblocks [start_block].addr;       
943                                 
944                                 //printf ("TEST %x %x %x\n", ei->try_start, ei->try_end, ei->handler_start);
945                         }
946                 }
947                 
948                 mono_jit_info_table_add (target_domain, ji);
949
950                 mono_regset_free (cfg->rs);
951
952                 mono_cfg_free (cfg);
953
954                 mono_mempool_destroy (mp);
955
956                 mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
957         }
958
959         if (mono_jit_trace_calls || mono_jit_dump_asm || mono_jit_dump_forest) {
960                 printf ("END JIT compilation of %s.%s:%s %p %p\n", method->klass->name_space,
961                         method->klass->name, method->name, method, addr);
962         }
963
964         g_hash_table_insert (jit_code_hash, method, addr);
965
966         return addr;
967 }
968