2002-03-15 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
23 #include "jit.h"
24 #include "codegen.h"
25 #include "debug.h"
26
27 static void
28 enter_method (MonoMethod *method, gpointer ebp)
29 {
30         int i, j;
31         MonoClass *class;
32         MonoObject *o;
33
34         printf ("ENTER: %s.%s::%s\n(", method->klass->name_space,
35                 method->klass->name, method->name);
36
37         
38         if (((int)ebp & 3) != 0) {
39                 g_error ("unaligned stack detected (%p)", ebp);
40         }
41
42         ebp += 8;
43
44         if (ISSTRUCT (method->signature->ret)) {
45                 int size, align;
46                 
47                 g_assert (!method->signature->ret->byref);
48
49                 size = mono_type_stack_size (method->signature->ret, &align);
50
51                 printf ("VALUERET:%p, ", *((gpointer *)ebp));
52                 ebp += sizeof (gpointer);
53         }
54
55         if (method->signature->hasthis) {
56                 if (method->klass->valuetype) {
57                         printf ("value:%p, ", *((gpointer *)ebp));
58                 } else {
59                         o = *((MonoObject **)ebp);
60
61                         g_assert (o);
62
63                         class = o->vtable->klass;
64
65                         if (class == mono_defaults.string_class) {
66                                 printf ("this:[STRING:%p:%s], ", o, mono_string_to_utf8 ((MonoString *)o));
67                         } else {
68                                 printf ("this:%p[%s.%s], ", o, class->name_space, class->name);
69                         }
70                 }
71                 ebp += sizeof (gpointer);
72         }
73
74         for (i = 0; i < method->signature->param_count; ++i) {
75                 MonoType *type = method->signature->params [i];
76                 int size, align;
77                 size = mono_type_stack_size (type, &align);
78
79                 if (type->byref) {
80                         printf ("[BYREF:%p], ", *((gpointer *)ebp)); 
81                 } else switch (type->type) {
82                         
83                 case MONO_TYPE_BOOLEAN:
84                 case MONO_TYPE_CHAR:
85                 case MONO_TYPE_I1:
86                 case MONO_TYPE_U1:
87                 case MONO_TYPE_I2:
88                 case MONO_TYPE_U2:
89                 case MONO_TYPE_I4:
90                 case MONO_TYPE_U4:
91                 case MONO_TYPE_I:
92                 case MONO_TYPE_U:
93                         printf ("%d, ", *((int *)(ebp)));
94                         break;
95                 case MONO_TYPE_STRING: {
96                         MonoString *s = *((MonoString **)ebp);
97                         if (s) {
98                                 g_assert (((MonoObject *)s)->vtable->klass == mono_defaults.string_class);
99                                 printf ("[STRING:%p:%s], ", s, mono_string_to_utf8 (s));
100                         } else 
101                                 printf ("[STRING:null], ");
102                         break;
103                 }
104                 case MONO_TYPE_CLASS:
105                 case MONO_TYPE_OBJECT: {
106                         o = *((MonoObject **)ebp);
107                         if (o) {
108                                 class = o->vtable->klass;
109                     
110                                 if (class == mono_defaults.string_class) {
111                                         printf ("[STRING:%p:%s], ", o, mono_string_to_utf8 ((MonoString *)o));
112                                 } else if (class == mono_defaults.int32_class) {
113                                         printf ("[INT32:%p:%d], ", o, *(gint32 *)((gpointer)o + sizeof (MonoObject)));
114                                 } else
115                                         printf ("[%s.%s:%p], ", class->name_space, class->name, o);
116                         } else {
117                                 printf ("%p, ", *((gpointer *)(ebp)));                          
118                         }
119                         break;
120                 }
121                 case MONO_TYPE_PTR:
122                 case MONO_TYPE_FNPTR:
123                 case MONO_TYPE_ARRAY:
124                 case MONO_TYPE_SZARRAY:
125                         printf ("%p, ", *((gpointer *)(ebp)));
126                         break;
127                 case MONO_TYPE_I8:
128                         printf ("%lld, ", *((gint64 *)(ebp)));
129                         break;
130                 case MONO_TYPE_R4:
131                         printf ("%f, ", *((float *)(ebp)));
132                         break;
133                 case MONO_TYPE_R8:
134                         printf ("%f, ", *((double *)(ebp)));
135                         break;
136                 case MONO_TYPE_VALUETYPE: 
137                         printf ("[");
138                         for (j = 0; j < size; j++)
139                                 printf ("%02x,", *((guint8*)ebp +j));
140                         printf ("], ");
141                         break;
142                 default:
143                         printf ("XX, ");
144                 }
145
146                 g_assert (align == 4);
147                 ebp += size + 3;
148                 ebp = (gpointer)((unsigned)ebp & ~(3));
149         }
150
151         printf (")\n");
152 }
153
154 static void
155 leave_method (MonoMethod *method, int edx, int eax, double test)
156 {
157         gint64 l;
158
159         printf ("LEAVE: %s.%s::%s ", method->klass->name_space,
160                 method->klass->name, method->name);
161
162         switch (method->signature->ret->type) {
163         case MONO_TYPE_VOID:
164                 break;
165         case MONO_TYPE_BOOLEAN:
166                 if (eax)
167                         printf ("TRUE:%d", eax);
168                 else 
169                         printf ("FALSE");
170                         
171                 break;
172         case MONO_TYPE_CHAR:
173         case MONO_TYPE_I1:
174         case MONO_TYPE_U1:
175         case MONO_TYPE_I2:
176         case MONO_TYPE_U2:
177         case MONO_TYPE_I4:
178         case MONO_TYPE_U4:
179         case MONO_TYPE_I:
180         case MONO_TYPE_U:
181                 printf ("EAX=%d", eax);
182                 break;
183         case MONO_TYPE_STRING: {
184                 MonoString *s = (MonoString *)eax;
185
186                 if (s) {
187                         g_assert (((MonoObject *)s)->vtable->klass == mono_defaults.string_class);
188                         printf ("[STRING:%p:%s]", s, mono_string_to_utf8 (s));
189                 } else 
190                         printf ("[STRING:null], ");
191                 break;
192         }
193         case MONO_TYPE_OBJECT: {
194                 MonoObject *o = (MonoObject *)eax;
195
196                 if (o) {
197                         if (o->vtable->klass == mono_defaults.boolean_class) {
198                                 printf ("[BOOLEAN:%p:%d]", o, *((guint8 *)o + sizeof (MonoObject)));            
199                         } else if  (o->vtable->klass == mono_defaults.int32_class) {
200                                 printf ("[INT32:%p:%d]", o, *((gint32 *)((gpointer)o + sizeof (MonoObject))));  
201                         } else
202                                 printf ("[%s.%s:%p]", o->vtable->klass->name_space, o->vtable->klass->name, o);
203                 } else
204                         printf ("[OBJECT:%p]", o);
205                
206                 break;
207         }
208         case MONO_TYPE_CLASS:
209         case MONO_TYPE_PTR:
210         case MONO_TYPE_FNPTR:
211         case MONO_TYPE_ARRAY:
212         case MONO_TYPE_SZARRAY:
213                 printf ("EAX=%p", (gpointer)eax);
214                 break;
215         case MONO_TYPE_I8:
216                 *((gint32 *)&l) = eax;
217                 *((gint32 *)&l + 1) = edx;
218                 printf ("EAX/EDX=%lld", l);
219                 break;
220         case MONO_TYPE_R8:
221                 printf ("FP=%f\n", test);
222                 break;
223         default:
224                 printf ("(unknown return type)");
225         }
226
227         printf ("\n");
228 }
229
230 /**
231  * arch_emit_prologue:
232  * @cfg: pointer to status information
233  *
234  * Emits the function prolog.
235  */
236 static void
237 arch_emit_prologue (MonoFlowGraph *cfg)
238 {
239         x86_push_reg (cfg->code, X86_EBP);
240         x86_mov_reg_reg (cfg->code, X86_EBP, X86_ESP, 4);
241
242         if (cfg->locals_size)
243                 x86_alu_reg_imm (cfg->code, X86_SUB, X86_ESP, cfg->locals_size);
244
245         if (mono_regset_reg_used (cfg->rs, X86_EBX)) 
246                 x86_push_reg (cfg->code, X86_EBX);
247
248         if (mono_regset_reg_used (cfg->rs, X86_EDI)) 
249                 x86_push_reg (cfg->code, X86_EDI);
250
251         if (mono_regset_reg_used (cfg->rs, X86_ESI))
252                 x86_push_reg (cfg->code, X86_ESI);
253
254         if (mono_jit_trace_calls) {
255                 x86_push_reg (cfg->code, X86_EBP);
256                 x86_push_imm (cfg->code, cfg->method);
257                 x86_mov_reg_imm (cfg->code, X86_EAX, enter_method);
258                 x86_call_reg (cfg->code, X86_EAX);
259                 x86_alu_reg_imm (cfg->code, X86_ADD, X86_ESP, 8);
260         }
261 }
262
263 /**
264  * arch_emit_epilogue:
265  * @cfg: pointer to status information
266  *
267  * Emits the function epilog.
268  */
269 static void
270 arch_emit_epilogue (MonoFlowGraph *cfg)
271 {
272         if (mono_jit_trace_calls) {
273                 x86_fld_reg (cfg->code, 0);
274                 x86_alu_reg_imm (cfg->code, X86_SUB, X86_ESP, 8);
275                 x86_fst_membase (cfg->code, X86_ESP, 0, TRUE, TRUE);
276                 x86_push_reg (cfg->code, X86_EAX);
277                 x86_push_reg (cfg->code, X86_EDX);
278                 x86_push_imm (cfg->code, cfg->method);
279                 x86_mov_reg_imm (cfg->code, X86_EAX, leave_method);
280                 x86_call_reg (cfg->code, X86_EAX);
281                 x86_alu_reg_imm (cfg->code, X86_ADD, X86_ESP, 4);
282                 x86_pop_reg (cfg->code, X86_EDX);
283                 x86_pop_reg (cfg->code, X86_EAX);
284                 x86_alu_reg_imm (cfg->code, X86_ADD, X86_ESP, 8);
285         }
286
287         if (mono_regset_reg_used (cfg->rs, X86_ESI))
288                 x86_pop_reg (cfg->code, X86_ESI);
289
290         if (mono_regset_reg_used (cfg->rs, X86_EDI))
291                 x86_pop_reg (cfg->code, X86_EDI);
292
293         if (mono_regset_reg_used (cfg->rs, X86_EBX))
294                 x86_pop_reg (cfg->code, X86_EBX);
295
296         x86_leave (cfg->code);
297         x86_ret (cfg->code);
298 }
299
300 /*
301  * get_unbox_trampoline:
302  * @m: method pointer
303  * @addr: pointer to native code for @m
304  *
305  * when value type methods are called through the vtable we need to unbox the
306  * this argument. This method returns a pointer to a trampoline which does
307  * unboxing before calling the method
308  */
309 static gpointer
310 get_unbox_trampoline (MonoMethod *m, gpointer addr)
311 {
312         guint8 *code, *start;
313         int this_pos = 4;
314
315         if (!m->signature->ret->byref && m->signature->ret->type == MONO_TYPE_VALUETYPE)
316                 this_pos = 8;
317             
318         start = code = g_malloc (16);
319
320         x86_alu_membase_imm (code, X86_ADD, X86_ESP, this_pos, sizeof (MonoObject));
321         x86_jump_code (code, addr);
322         g_assert ((code - start) < 16);
323
324         return start;
325 }
326
327 /**
328  * x86_magic_trampoline:
329  * @eax: saved x86 register 
330  * @ecx: saved x86 register 
331  * @edx: saved x86 register 
332  * @esi: saved x86 register 
333  * @edi: saved x86 register 
334  * @ebx: saved x86 register
335  * @code: pointer into caller code
336  * @method: the method to translate
337  *
338  * This method is called by the trampoline functions for virtual
339  * methods. It inspects the caller code to find the address of the
340  * vtable slot, then calls the JIT compiler and writes the address
341  * of the compiled method back to the vtable. All virtual methods 
342  * are called with: x86_call_membase (inst, basereg, disp). We always
343  * use 32 bit displacement to ensure that the length of the call 
344  * instruction is 6 bytes. We need to get the value of the basereg 
345  * and the constant displacement.
346  */
347 static gpointer
348 x86_magic_trampoline (int eax, int ecx, int edx, int esi, int edi, 
349                       int ebx, const guint8 *code, MonoMethod *m)
350 {
351         guint8 reg;
352         gint32 disp;
353         gpointer o;
354         gpointer addr;
355
356         EnterCriticalSection (metadata_section);
357         addr = arch_compile_method (m);
358         LeaveCriticalSection (metadata_section);
359         g_assert (addr);
360
361
362         /* go to the start of the call instruction
363          *
364          * address_byte = (m << 6) | (o << 3) | reg
365          * call opcode: 0xff address_byte displacement
366          * 0xff m=1,o=2 imm8
367          * 0xff m=2,o=2 imm32
368          */
369         code -= 6;
370         if ((code [1] != 0xe8) && (code [3] == 0xff) && ((code [4] & 0x18) == 0x10) && ((code [4] >> 6) == 1)) {
371                 reg = code [4] & 0x07;
372                 disp = (signed char)code [5];
373         } else {
374                 if ((code [0] == 0xff) && ((code [1] & 0x18) == 0x10) && ((code [1] >> 6) == 2)) {
375                         reg = code [1] & 0x07;
376                         disp = *((gint32*)(code + 2));
377                 } else if ((code [1] == 0xe8)) {
378                         *((guint32*)(code + 2)) = (guint)addr - ((guint)code + 1) - 5; 
379                         return addr;
380                 } else {
381                         printf ("%x %x %x %x %x %x \n", code [0], code [1], code [2], code [3],
382                                 code [4], code [5]);
383                         g_assert_not_reached ();
384                 }
385         }
386
387         switch (reg) {
388         case X86_EAX:
389                 o = (gpointer)eax;
390                 break;
391         case X86_EDX:
392                 o = (gpointer)edx;
393                 break;
394         case X86_ECX:
395                 o = (gpointer)ecx;
396                 break;
397         case X86_ESI:
398                 o = (gpointer)esi;
399                 break;
400         case X86_EDI:
401                 o = (gpointer)edi;
402                 break;
403         case X86_EBX:
404                 o = (gpointer)ebx;
405                 break;
406         default:
407                 g_assert_not_reached ();
408         }
409
410         o += disp;
411
412         if (m->klass->valuetype) {
413                 return *((gpointer *)o) = get_unbox_trampoline (m, addr);
414         } else {
415                 return *((gpointer *)o) = addr;
416         }
417 }
418
419 /**
420  * arch_create_jit_trampoline:
421  * @method: pointer to the method info
422  *
423  * Creates a trampoline function for virtual methods. If the created
424  * code is called it first starts JIT compilation of method,
425  * and then calls the newly created method. I also replaces the
426  * corresponding vtable entry (see x86_magic_trampoline).
427  * 
428  * Returns: a pointer to the newly created code 
429  */
430 gpointer
431 arch_create_jit_trampoline (MonoMethod *method)
432 {
433         MonoDomain *domain = mono_domain_get ();
434         guint8 *code, *buf;
435         static guint8 *vc = NULL;
436         GHashTable *jit_code_hash;
437
438         /* previously created trampoline code */
439         if (method->info)
440                 return method->info;
441
442         /* icalls use method->addr */
443         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
444             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
445                 method->info = arch_create_native_wrapper (method);
446                 return method->info;
447         }
448
449         /* check if we already have JITed code */
450         if (mono_jit_share_code)
451                 jit_code_hash = mono_root_domain->jit_code_hash;
452         else
453                 jit_code_hash = domain->jit_code_hash;
454
455         if ((code = g_hash_table_lookup (jit_code_hash, method))) {
456                 mono_jit_stats.methods_lookups++;
457                 return code;
458         }
459
460         if (!vc) {
461                 vc = buf = g_malloc (256);
462
463                 /* save caller save regs because we need to do a call */ 
464                 x86_push_reg (buf, X86_EDX);
465                 x86_push_reg (buf, X86_EAX);
466                 x86_push_reg (buf, X86_ECX);
467
468                 /* save LMF begin */
469
470                 /* save the IP (caller ip) */
471                 x86_push_membase (buf, X86_ESP, 16);
472
473                 x86_push_reg (buf, X86_EBX);
474                 x86_push_reg (buf, X86_EDI);
475                 x86_push_reg (buf, X86_ESI);
476                 x86_push_reg (buf, X86_EBP);
477
478                 /* save method info */
479                 x86_push_membase (buf, X86_ESP, 32);
480                 /* get the address of lmf for the current thread */
481                 x86_call_code (buf, arch_get_lmf_addr);
482                 /* push lmf */
483                 x86_push_reg (buf, X86_EAX); 
484                 /* push *lfm (previous_lmf) */
485                 x86_push_membase (buf, X86_EAX, 0);
486                 /* *(lmf) = ESP */
487                 x86_mov_membase_reg (buf, X86_EAX, 0, X86_ESP, 4);
488                 /* save LFM end */
489
490                 /* push the method info */
491                 x86_push_membase (buf, X86_ESP, 44);
492                 /* push the return address onto the stack */
493                 x86_push_membase (buf, X86_ESP, 52);
494
495                 /* save all register values */
496                 x86_push_reg (buf, X86_EBX);
497                 x86_push_reg (buf, X86_EDI);
498                 x86_push_reg (buf, X86_ESI);
499                 x86_push_membase (buf, X86_ESP, 64); /* EDX */
500                 x86_push_membase (buf, X86_ESP, 64); /* ECX */
501                 x86_push_membase (buf, X86_ESP, 64); /* EAX */
502
503                 x86_call_code (buf, x86_magic_trampoline);
504                 x86_alu_reg_imm (buf, X86_ADD, X86_ESP, 8*4);
505
506                 /* restore LMF start */
507                 /* ebx = previous_lmf */
508                 x86_pop_reg (buf, X86_EBX);
509                 /* edi = lmf */
510                 x86_pop_reg (buf, X86_EDI);
511                 /* *(lmf) = previous_lmf */
512                 x86_mov_membase_reg (buf, X86_EDI, 0, X86_EBX, 4);
513                 /* discard method info */
514                 x86_pop_reg (buf, X86_ESI);
515                 /* restore caller saved regs */
516                 x86_pop_reg (buf, X86_EBP);
517                 x86_pop_reg (buf, X86_ESI);
518                 x86_pop_reg (buf, X86_EDI);
519                 x86_pop_reg (buf, X86_EBX);
520                 /* discard save IP */
521                 x86_alu_reg_imm (buf, X86_ADD, X86_ESP, 4);             
522                 /* restore LMF end */
523
524                 x86_alu_reg_imm (buf, X86_ADD, X86_ESP, 16);
525
526                 /* call the compiled method */
527                 x86_jump_reg (buf, X86_EAX);
528
529                 g_assert ((buf - vc) <= 256);
530         }
531
532         code = buf = g_malloc (16);
533         x86_push_imm (buf, method);
534         x86_jump_code (buf, vc);
535         g_assert ((buf - code) <= 16);
536
537         /* store trampoline address */
538         method->info = code;
539
540         mono_jit_stats.method_trampolines++;
541
542         return code;
543 }
544
545 static void
546 mono_label_cfg (MonoFlowGraph *cfg)
547 {
548         int i, j;
549         
550         for (i = 0; i < cfg->block_count; i++) {
551                 GPtrArray *forest = cfg->bblocks [i].forest;
552                 int top;
553
554                 if (!cfg->bblocks [i].reached) /* unreachable code */
555                         continue;
556                 
557                 top = forest->len;
558
559                 for (j = 0; j < top; j++) {
560                         MBTree *t1 = (MBTree *) g_ptr_array_index (forest, j);
561                         MBState *mbstate;
562
563                         mbstate =  mono_burg_label (t1, cfg);
564                         if (!mbstate) {
565                                 cfg->invalid = 1;
566                                 if (mono_debug_handle)
567                                         return;
568                                 g_warning ("tree does not match");
569                                 mono_print_ctree (t1); printf ("\n\n");
570
571                                 mono_print_forest (forest);
572                                 g_assert_not_reached ();
573                         }
574                 }
575         }
576 }
577
578 static void
579 tree_preallocate_regs (MBTree *tree, int goal, MonoRegSet *rs) 
580 {
581         switch (tree->op) {
582         case MB_TERM_CALL_I4:
583         case MB_TERM_CALL_I8:
584         case MB_TERM_CALL_R8:
585 //      case MB_TERM_CALL_VOID :
586                 tree->reg1 = mono_regset_alloc_reg (rs, X86_EAX, tree->exclude_mask);
587                 tree->reg2 = mono_regset_alloc_reg (rs, X86_EDX, tree->exclude_mask);
588                 tree->reg3 = mono_regset_alloc_reg (rs, X86_ECX, tree->exclude_mask);
589                 return;
590         default: break;
591         }
592
593         switch (goal) {
594         case MB_NTERM_reg:
595         case MB_NTERM_lreg: {
596                 switch (tree->op) {
597                 case MB_TERM_SHL:
598                 case MB_TERM_SHR:
599                 case MB_TERM_SHR_UN:
600                         tree->exclude_mask |= (1 << X86_ECX);
601                         tree->left->exclude_mask |= (1 << X86_ECX);
602                         break;
603                 case MB_TERM_MUL:
604                 case MB_TERM_MUL_OVF:
605                 case MB_TERM_MUL_OVF_UN:
606                 case MB_TERM_DIV:
607                 case MB_TERM_DIV_UN:
608                 case MB_TERM_REM:
609                 case MB_TERM_REM_UN:
610                         tree->reg1 = mono_regset_alloc_reg (rs, X86_EAX, tree->exclude_mask);
611                         tree->reg2 = mono_regset_alloc_reg (rs, X86_EDX, tree->exclude_mask);
612                         if (goal == MB_NTERM_reg) {
613                                 tree->left->exclude_mask |= (1 << X86_EDX);
614                                 tree->right->exclude_mask |= (1 << X86_EDX) | (1 << X86_EAX);
615                         }
616                         break;
617                 default:
618                         break;
619                 }
620                 break;
621         }
622         default:
623                 break;
624         }
625 }
626
627 static void
628 tree_allocate_regs (MBTree *tree, int goal, MonoRegSet *rs) 
629 {
630         MBTree *kids[10];
631         int ern = mono_burg_rule (tree->state, goal);
632         const guint16 *nts = mono_burg_nts [ern];
633         int i;
634         
635         mono_burg_kids (tree, ern, kids);
636
637         //printf ("RALLOC START %d %p %d\n",  tree->op, rs->free_mask, goal);
638
639         if (nts [0] && kids [0] == tree) {
640                 /* chain rule */
641                 tree_allocate_regs (kids [0], nts [0], rs);
642                 return;
643         }
644
645         for (i = 0; nts [i]; i++)
646                 tree_preallocate_regs (kids [i], nts [i], rs);
647
648         for (i = 0; nts [i]; i++)
649                 tree_allocate_regs (kids [i], nts [i], rs);
650
651         for (i = 0; nts [i]; i++) {
652                 mono_regset_free_reg (rs, kids [i]->reg1);
653                 mono_regset_free_reg (rs, kids [i]->reg2);
654                 mono_regset_free_reg (rs, kids [i]->reg3);
655         }
656
657         switch (goal) {
658         case MB_NTERM_reg:
659                 if (tree->reg1 < 0) { 
660                         tree->reg1 = mono_regset_alloc_reg (rs, -1, tree->exclude_mask);
661                         g_assert (tree->reg1 != -1);
662                 }
663                 break;
664
665         case MB_NTERM_lreg:
666                 if (tree->reg1 < 0) { 
667                         tree->reg1 = mono_regset_alloc_reg (rs, -1, tree->exclude_mask);
668                         g_assert (tree->reg1 != -1);
669                 }
670                 if (tree->reg2 < 0) { 
671                         tree->reg2 = mono_regset_alloc_reg (rs, -1, tree->exclude_mask);
672                         g_assert (tree->reg2 != -1);
673                 }
674                 break;
675
676         case MB_NTERM_freg:
677                 /* fixme: allocate floating point registers */
678                 break;
679       
680         case MB_NTERM_addr:
681                 if (tree->op == MB_TERM_ADD) {
682                         tree->reg1 = mono_regset_alloc_reg (rs, tree->left->reg1, tree->exclude_mask);
683                         tree->reg2 = mono_regset_alloc_reg (rs, tree->right->reg1, tree->exclude_mask);
684                 }
685                 break;
686                 
687         case MB_NTERM_base:
688                 if (tree->op == MB_TERM_ADD) {
689                         tree->reg1 = mono_regset_alloc_reg (rs, tree->left->reg1, tree->exclude_mask);
690                 }
691                 break;
692                
693         case MB_NTERM_index:
694                 if (tree->op == MB_TERM_SHL ||
695                     tree->op == MB_TERM_MUL) {
696                         tree->reg1 = mono_regset_alloc_reg (rs, tree->left->reg1, tree->exclude_mask);
697                 }
698                 break;
699                
700         default:
701                 /* do nothing */
702         }
703
704         //printf ("RALLOC END %d %p\n",  tree->op, rs->free_mask);
705         tree->emit = mono_burg_func [ern];
706 }
707
708 static void
709 arch_allocate_regs (MonoFlowGraph *cfg)
710 {
711         int i, j;
712         
713         for (i = 0; i < cfg->block_count; i++) {
714                 GPtrArray *forest = cfg->bblocks [i].forest;
715                 int top;
716
717                 if (!cfg->bblocks [i].reached) /* unreachable code */
718                         continue;
719
720                 top = forest->len;
721
722                 for (j = 0; j < top; j++) {
723                         MBTree *t1 = (MBTree *) g_ptr_array_index (forest, j);
724                         //printf ("AREGSTART %d:%d %p\n", i, j, cfg->rs->free_mask);
725                         tree_allocate_regs (t1, 1, cfg->rs);
726                         //printf ("AREGENDT %d:%d %p\n", i, j, cfg->rs->free_mask);
727                         g_assert (cfg->rs->free_mask == 0xffffffff);
728                 }
729         }
730 }
731
732 static void
733 tree_emit (int goal, MonoFlowGraph *cfg, MBTree *tree) 
734 {
735         MBTree *kids[10];
736         int i, ern = mono_burg_rule (tree->state, goal);
737         const guint16 *nts = mono_burg_nts [ern];
738         MBEmitFunc emit;
739         int offset;
740
741         mono_burg_kids (tree, ern, kids);
742
743         for (i = 0; nts [i]; i++) 
744                 tree_emit (nts [i], cfg, kids [i]);
745
746         tree->addr = offset = cfg->code - cfg->start;
747
748         // we assume an instruction uses a maximum of 128 bytes
749         if ((cfg->code_size - offset) <= 128) {
750                 int add = MIN (cfg->code_size, 128);
751                 cfg->code_size += add;
752                 mono_jit_stats.code_reallocs++;
753                 cfg->start = g_realloc (cfg->start, cfg->code_size);
754                 g_assert (cfg->start);
755                 cfg->code = cfg->start + offset;
756         }
757
758         if ((emit = mono_burg_func [ern]))
759                 emit (tree, cfg);
760
761         g_assert ((cfg->code - cfg->start) < cfg->code_size);
762 }
763
764 static void
765 mono_emit_cfg (MonoFlowGraph *cfg)
766 {
767         int i, j;
768
769         for (i = 0; i < cfg->block_count; i++) {
770                 MonoBBlock *bb = &cfg->bblocks [i];
771                 GPtrArray *forest = bb->forest;
772                 int top;
773
774                 if (!bb->reached) /* unreachable code */
775                         continue;
776                 
777                 top = forest->len;
778
779                 bb->addr = cfg->code - cfg->start;
780           
781                 for (j = 0; j < top; j++) {
782                         MBTree *t1 = (MBTree *) g_ptr_array_index (forest, j);
783                         
784                         tree_emit (1, cfg, t1);
785                 }
786         }
787                 
788         cfg->epilog = cfg->code - cfg->start;
789 }
790
791 static void
792 mono_compute_branches (MonoFlowGraph *cfg)
793 {
794         MonoJumpInfo *ji;
795         guint8 *end;
796         int i, j;
797
798         end = cfg->code;
799
800         for (j = 0; j < cfg->block_count; j++) {
801                 MonoBBlock *bb = &cfg->bblocks [j];
802                 GPtrArray *forest = bb->forest;
803                 int top;
804                 
805                 if (!bb->reached) /* unreachable code */
806                         continue;
807
808                 top = forest->len;
809         
810                 for (i = 0; i < top; i++) {
811                         MBTree *t1 = (MBTree *) g_ptr_array_index (forest, i);
812
813                         if (t1->op == MB_TERM_SWITCH) {
814                                 MonoBBlock **jt = (MonoBBlock **)t1->data.p;
815                                 guint32 *rt = (guint32 *)t1->data.p;
816                                 
817                                 int m = *((guint32 *)t1->data.p) + 1;
818                                 int j;
819                                 
820                                 for (j = 1; j <= m; j++)
821                                         rt [j] = (int)(jt [j]->addr + cfg->start);
822                                 
823                                 /* emit the switch instruction again to update addresses */
824                                 cfg->code = cfg->start + t1->addr;
825                                 ((MBEmitFunc)t1->emit) (t1, cfg);
826                         }
827                 }
828         }
829
830         cfg->code = end;
831
832         for (ji = cfg->jump_info; ji; ji = ji->next) {
833                 gpointer *ip = GUINT_TO_POINTER (GPOINTER_TO_UINT (ji->ip) + cfg->start);
834                 gpointer target;
835
836                 switch (ji->type) {
837                 case MONO_JUMP_INFO_BB:
838                         target = ji->data.bb->addr + cfg->start;
839                         *ip = target - GPOINTER_TO_UINT(ip) - 4;
840                         break;
841                 case MONO_JUMP_INFO_ABS:
842                         target = ji->data.target;
843                         *ip = target - GPOINTER_TO_UINT(ip) - 4;
844                         break;
845                 case MONO_JUMP_INFO_EPILOG:
846                         target = cfg->epilog + cfg->start;
847                         *ip = target - GPOINTER_TO_UINT(ip) - 4;
848                         break;
849                 case MONO_JUMP_INFO_IP:
850                         *ip = ip;
851                         break;
852                 default:
853                         g_assert_not_reached ();
854                 }
855         }
856 }
857
858 void
859 mono_add_jump_info (MonoFlowGraph *cfg, gpointer ip, MonoJumpInfoType type, gpointer target)
860 {
861         MonoJumpInfo *ji = mono_mempool_alloc (cfg->mp, sizeof (MonoJumpInfo));
862
863         ji->type = type;
864         ji->ip = GUINT_TO_POINTER (GPOINTER_TO_UINT (ip) - GPOINTER_TO_UINT (cfg->start));
865         ji->data.target = target;
866         ji->next = cfg->jump_info;
867
868         cfg->jump_info = ji;
869 }
870
871 static int
872 match_debug_method (MonoMethod* method)
873 {
874         GList *tmp = mono_debug_methods;
875
876         for (; tmp; tmp = tmp->next) {
877                 if (mono_method_desc_full_match (tmp->data, method))
878                         return 1;
879         }
880         return 0;
881 }
882
883 static void
884 mono_delegate_ctor (MonoDelegate *this, MonoObject *target, 
885                     gpointer addr)
886 {
887         MonoDomain *domain = mono_domain_get ();
888         MonoClass *class;
889         MonoJitInfo *ji;
890
891         g_assert (this);
892         g_assert (addr);
893
894         class = this->object.vtable->klass;
895
896         if ((ji = mono_jit_info_table_find (domain, addr))) {
897                 this->method_info = mono_method_get_object (domain, ji->method);
898         }
899         
900         this->target = target;
901         this->method_ptr = addr;
902
903 }
904
905 /**
906  * arch_compile_method:
907  * @method: pointer to the method info
908  *
909  * JIT compilation of a single method. 
910  *
911  * Returns: a pointer to the newly created code.
912  */
913 gpointer
914 arch_compile_method (MonoMethod *method)
915 {
916         MonoDomain *target_domain, *domain = mono_domain_get ();
917         MonoJitInfo *ji;
918         MonoMemPool *mp;
919         guint8 *addr;
920         GHashTable *jit_code_hash;
921
922         g_assert (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL));
923
924         if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
925                 if (!method->info)
926                         method->info = arch_create_native_wrapper (method);
927                 return method->info;
928         }
929
930         if (mono_jit_share_code)
931                 target_domain = mono_root_domain;
932         else 
933                 target_domain = domain;
934
935         jit_code_hash = target_domain->jit_code_hash;
936
937         if ((addr = g_hash_table_lookup (jit_code_hash, method))) {
938                 mono_jit_stats.methods_lookups++;
939                 return addr;
940         }
941
942         mono_jit_stats.methods_compiled++;
943         
944         mp = mono_mempool_new ();
945
946         if (mono_jit_trace_calls || mono_jit_dump_asm || mono_jit_dump_forest) {
947                 printf ("Start JIT compilation of %s.%s:%s\n", method->klass->name_space,
948                         method->klass->name, method->name);
949         }
950
951         if (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
952                 const char *name = method->name;
953                 guint8 *code;
954                 gboolean delegate = FALSE;
955
956                 if (method->klass->parent == mono_defaults.multicastdelegate_class)
957                         delegate = TRUE;
958                                 
959                 if (delegate && *name == '.' && (strcmp (name, ".ctor") == 0)) {
960                         addr = (gpointer)mono_delegate_ctor;
961                 } else if (delegate && *name == 'I' && (strcmp (name, "Invoke") == 0)) {
962                         /*
963                          *      Invoke( args .. ) {
964                          *              if ( prev )
965                          *                      prev.Invoke();
966                          *              return this.<m_target>( args );
967                          *      }
968                          */
969                         MonoMethodSignature *csig = method->signature;
970                         guint8 *br[2], *pos[2];
971                         int i, arg_size, this_pos = 4;
972                         
973                         if (csig->ret->type == MONO_TYPE_VALUETYPE) {
974                                 g_assert (!csig->ret->byref);
975                                 this_pos = 8;
976                         }
977
978                         arg_size = 0;
979                         if (csig->param_count) {
980                                 int align;
981                                 
982                                 for (i = 0; i < csig->param_count; ++i) {
983                                         arg_size += mono_type_stack_size (csig->params [i], &align);
984                                         g_assert (align == 4);
985                                 }
986                         }
987
988                         addr = g_malloc (64 + arg_size);
989
990                         code = addr;
991                         /* load the this pointer */
992                         x86_mov_reg_membase (code, X86_EAX, X86_ESP, this_pos, 4);
993                         
994                         /* load prev */
995                         x86_mov_reg_membase (code, X86_EDX, X86_EAX, G_STRUCT_OFFSET (MonoMulticastDelegate, prev), 4);
996
997                         /* prev == 0 ? */
998                         x86_alu_reg_imm (code, X86_CMP, X86_EDX, 0);
999                         br[0] = code; x86_branch32 (code, X86_CC_EQ, 0, TRUE );
1000                         pos[0] = code;
1001
1002                         x86_push_reg( code, X86_EAX );
1003                         /* push args */
1004                         for ( i = 0; i < (arg_size>>2); i++ )
1005                                 x86_push_membase( code, X86_ESP, (arg_size + this_pos + 4) );
1006                         /* push next */
1007                         x86_push_reg( code, X86_EDX );
1008                         if (this_pos == 8)
1009                                 x86_push_membase (code, X86_ESP, (arg_size + 8));
1010                         /* recurse */
1011                         br[1] = code; x86_call_imm( code, 0 );
1012                         pos[1] = code; x86_call_imm( br[1], addr - pos[1] );
1013
1014                         if (this_pos == 8)
1015                                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, arg_size + 8);
1016                         else
1017                                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, arg_size + 4);
1018                         x86_pop_reg( code, X86_EAX );
1019                         
1020                         /* prev == 0 */ 
1021                         x86_branch32( br[0], X86_CC_EQ, code - pos[0], TRUE );
1022                         
1023                         /* load mtarget */
1024                         x86_mov_reg_membase (code, X86_EDX, X86_EAX, G_STRUCT_OFFSET (MonoDelegate, target), 4); 
1025                         /* mtarget == 0 ? */
1026                         x86_alu_reg_imm (code, X86_CMP, X86_EDX, 0);
1027                         br[0] = code; x86_branch32 (code, X86_CC_EQ, 0, TRUE);
1028                         pos[0] = code;
1029
1030                         /* 
1031                          * virtual delegate methods: we have to
1032                          * replace the this pointer with the actual
1033                          * target
1034                          */
1035                         x86_mov_membase_reg (code, X86_ESP, this_pos, X86_EDX, 4); 
1036                         /* jump to method_ptr() */
1037                         x86_jump_membase (code, X86_EAX, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
1038
1039                         /* mtarget != 0 */ 
1040                         x86_branch32( br[0], X86_CC_EQ, code - pos[0], TRUE);
1041                         /* 
1042                          * static delegate methods: we have to remove
1043                          * the this pointer from the activation frame
1044                          * - I do this creating a new stack frame anx
1045                          * copy all arguments except the this pointer
1046                          */
1047                         g_assert ((arg_size & 3) == 0);
1048                         for (i = 0; i < (arg_size>>2); i++) {
1049                                 x86_push_membase (code, X86_ESP, (arg_size + this_pos));
1050                         }
1051
1052                         if (this_pos == 8)
1053                                 x86_push_membase (code, X86_ESP, (arg_size + 4));
1054                         
1055                         x86_call_membase (code, X86_EAX, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
1056                         if (arg_size) {
1057                                 if (this_pos == 8) 
1058                                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, arg_size + 4);
1059                                 else
1060                                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, arg_size);
1061                         }
1062
1063                         x86_ret (code);
1064                 
1065                         g_assert ((code - (guint8*)addr) < (64 + arg_size));
1066
1067                         if (mono_jit_dump_asm) {
1068                                 char *id = g_strdup_printf ("%s.%s_%s", method->klass->name_space,
1069                                                             method->klass->name, method->name);
1070                                 mono_disassemble_code( addr, code - (guint8*)addr, id );
1071                                 g_free (id);
1072                         }
1073                 } else {
1074                         if (mono_debug_handle) 
1075                                 return NULL;
1076
1077                         g_error ("Don't know how to exec runtime method %s.%s::%s", 
1078                                  method->klass->name_space, method->klass->name, method->name);
1079                 }
1080         
1081         } else {
1082                 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
1083                 MonoFlowGraph *cfg;
1084
1085                 gulong code_size_ratio;
1086
1087                 ji = mono_mempool_alloc0 (target_domain->mp, sizeof (MonoJitInfo));
1088                 
1089                 cfg = mono_cfg_new (method, mp);
1090
1091                 mono_analyze_flow (cfg);
1092                 if (cfg->invalid) 
1093                         return NULL;
1094                 
1095                 mono_analyze_stack (cfg);
1096                 if (cfg->invalid) 
1097                         return NULL;
1098                 
1099                 cfg->rs = mono_regset_new (X86_NREG);
1100                 mono_regset_reserve_reg (cfg->rs, X86_ESP);
1101                 mono_regset_reserve_reg (cfg->rs, X86_EBP);
1102
1103                 cfg->code_size = MAX (header->code_size * 5, 256);
1104                 cfg->start = cfg->code = g_malloc (cfg->code_size);
1105
1106                 if (match_debug_method (method))
1107                         x86_breakpoint (cfg->code);
1108                 else if (mono_debug_handle)
1109                         x86_nop (cfg->code);
1110
1111                 if (mono_jit_dump_forest) {
1112                         int i;
1113                         printf ("FOREST %s.%s:%s\n", method->klass->name_space,
1114                                 method->klass->name, method->name);
1115                         for (i = 0; i < cfg->block_count; i++) {
1116                                 printf ("BLOCK %d:\n", i);
1117                                 mono_print_forest (cfg->bblocks [i].forest);
1118                         }
1119                 }
1120         
1121                 mono_label_cfg (cfg);
1122                 if (cfg->invalid) 
1123                         return NULL;
1124                 
1125                 arch_allocate_regs (cfg);
1126
1127                 /* align to 8 byte boundary */
1128                 cfg->locals_size += 7;
1129                 cfg->locals_size &= ~7;
1130
1131                 arch_emit_prologue (cfg);
1132                 mono_emit_cfg (cfg);
1133                 arch_emit_epilogue (cfg);               
1134
1135                 addr = cfg->start;
1136
1137                 mono_jit_stats.allocated_code_size += cfg->code_size;
1138
1139                 code_size_ratio = cfg->code - cfg->start;
1140                 if (code_size_ratio > mono_jit_stats.biggest_method_size) {
1141                         mono_jit_stats.biggest_method_size = code_size_ratio;
1142                         mono_jit_stats.biggest_method = method;
1143                 }
1144                 code_size_ratio = (code_size_ratio * 100) / header->code_size;
1145                 if (code_size_ratio > mono_jit_stats.max_code_size_ratio) {
1146                         mono_jit_stats.max_code_size_ratio = code_size_ratio;
1147                         mono_jit_stats.max_ratio_method = method;
1148                 }
1149
1150                 mono_compute_branches (cfg);
1151                 
1152                 if (mono_jit_dump_asm) {
1153                         char *id = g_strdup_printf ("%s.%s_%s", method->klass->name_space,
1154                                                     method->klass->name, method->name);
1155                         mono_disassemble_code (cfg->start, cfg->code - cfg->start, id);
1156                         g_free (id);
1157                 }
1158                 if (mono_debug_handle)
1159                         mono_debug_add_method (mono_debug_handle, cfg);
1160
1161                 ji->code_size = cfg->code - cfg->start;
1162                 ji->used_regs = cfg->rs->used_mask;
1163                 ji->method = method;
1164                 ji->code_start = addr;
1165
1166                 mono_jit_stats.native_code_size += ji->code_size;
1167
1168                 if (header->num_clauses) {
1169                         int i, start_block, end_block;
1170
1171                         ji->num_clauses = header->num_clauses;
1172                         ji->clauses = mono_mempool_alloc0 (target_domain->mp, 
1173                                 sizeof (MonoJitExceptionInfo) * header->num_clauses);
1174
1175                         for (i = 0; i < header->num_clauses; i++) {
1176                                 MonoExceptionClause *ec = &header->clauses [i];
1177                                 MonoJitExceptionInfo *ei = &ji->clauses [i];
1178                         
1179                                 ei->flags = ec->flags;
1180                                 ei->token_or_filter = ec->token_or_filter;
1181
1182                                 g_assert (cfg->bcinfo [ec->try_offset].is_block_start);
1183                                 start_block = cfg->bcinfo [ec->try_offset].block_id;
1184                                 end_block = cfg->bcinfo [ec->try_offset + ec->try_len].block_id;
1185                                 g_assert (cfg->bcinfo [ec->try_offset + ec->try_len].is_block_start);
1186                                 
1187                                 ei->try_start = cfg->start + cfg->bblocks [start_block].addr;
1188                                 ei->try_end = cfg->start + cfg->bblocks [end_block].addr;
1189                                 
1190                                 g_assert (cfg->bcinfo [ec->handler_offset].is_block_start);
1191                                 start_block = cfg->bcinfo [ec->handler_offset].block_id;
1192                                 ei->handler_start = cfg->start + cfg->bblocks [start_block].addr;       
1193                                 
1194                                 //printf ("TEST %x %x %x\n", ei->try_start, ei->try_end, ei->handler_start);
1195                         }
1196                 }
1197                 
1198                 mono_jit_info_table_add (target_domain, ji);
1199
1200                 mono_regset_free (cfg->rs);
1201
1202                 mono_cfg_free (cfg);
1203
1204                 mono_mempool_destroy (mp);
1205
1206         }
1207
1208         if (mono_jit_trace_calls || mono_jit_dump_asm || mono_jit_dump_forest) {
1209                 printf ("END JIT compilation of %s.%s:%s %p %p\n", method->klass->name_space,
1210                         method->klass->name, method->name, method, addr);
1211         }
1212
1213         g_hash_table_insert (jit_code_hash, method, addr);
1214
1215         return addr;
1216 }
1217
1218 /*
1219  * arch_get_restore_context:
1220  *
1221  * Returns a pointer to a method which restores a previously saved sigcontext.
1222  */
1223 static gpointer
1224 arch_get_restore_context ()
1225 {
1226         static guint8 *start = NULL;
1227         guint8 *code;
1228
1229         if (start)
1230                 return start;
1231
1232         /* restore_contect (struct sigcontext *ctx) */
1233         /* we do not restore X86_EAX, X86_EDX */
1234
1235         start = code = g_malloc (1024);
1236         
1237         /* load ctx */
1238         x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
1239
1240         /* get return address, stored in EDX */
1241         x86_mov_reg_membase (code, X86_EDX, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, eip), 4);
1242         /* restore EBX */
1243         x86_mov_reg_membase (code, X86_EBX, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, ebx), 4);
1244         /* restore EDI */
1245         x86_mov_reg_membase (code, X86_EDI, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, edi), 4);
1246         /* restore ESI */
1247         x86_mov_reg_membase (code, X86_ESI, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, esi), 4);
1248         /* restore ESP */
1249         x86_mov_reg_membase (code, X86_ESP, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, esp), 4);
1250         /* restore EBP */
1251         x86_mov_reg_membase (code, X86_EBP, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, ebp), 4);
1252         /* restore ECX. the exception object is passed here to the catch handler */
1253         x86_mov_reg_membase (code, X86_ECX, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, ecx), 4);
1254
1255         /* jump to the saved IP */
1256         x86_jump_reg (code, X86_EDX);
1257
1258         return start;
1259 }
1260
1261 /*
1262  * arch_get_call_finally:
1263  *
1264  * Returns a pointer to a method which calls a finally handler.
1265  */
1266 static gpointer
1267 arch_get_call_finally ()
1268 {
1269         static guint8 start [28];
1270         static int inited = 0;
1271         guint8 *code;
1272
1273         if (inited)
1274                 return start;
1275
1276         inited = 1;
1277         /* call_finally (struct sigcontext *ctx, unsigned long eip) */
1278         code = start;
1279
1280         x86_push_reg (code, X86_EBP);
1281         x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
1282         x86_push_reg (code, X86_EBX);
1283         x86_push_reg (code, X86_EDI);
1284         x86_push_reg (code, X86_ESI);
1285
1286         /* load ctx */
1287         x86_mov_reg_membase (code, X86_EAX, X86_EBP, 8, 4);
1288         /* load eip */
1289         x86_mov_reg_membase (code, X86_ECX, X86_EBP, 12, 4);
1290         /* save EBP */
1291         x86_push_reg (code, X86_EBP);
1292         /* set new EBP */
1293         x86_mov_reg_membase (code, X86_EBP, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, ebp), 4);
1294         /* call the handler */
1295         x86_call_reg (code, X86_ECX);
1296         /* restore EBP */
1297         x86_pop_reg (code, X86_EBP);
1298         /* restore saved regs */
1299         x86_pop_reg (code, X86_ESI);
1300         x86_pop_reg (code, X86_EDI);
1301         x86_pop_reg (code, X86_EBX);
1302         x86_leave (code);
1303         x86_ret (code);
1304
1305         g_assert ((code - start) < 28);
1306         return start;
1307 }
1308
1309 /**
1310  * arch_handle_exception:
1311  * @ctx: saved processor state
1312  * @obj:
1313  */
1314 void
1315 arch_handle_exception (struct sigcontext *ctx, gpointer obj)
1316 {
1317         MonoDomain *domain = mono_domain_get ();
1318         MonoJitInfo *ji;
1319         gpointer ip = (gpointer)ctx->eip;
1320         static void (*restore_context) (struct sigcontext *);
1321         static void (*call_finally) (struct sigcontext *, unsigned long);
1322        
1323         g_assert (ctx != NULL);
1324         g_assert (obj != NULL);
1325
1326         ji = mono_jit_info_table_find (domain, ip);
1327
1328         if (!restore_context)
1329                 restore_context = arch_get_restore_context ();
1330         
1331         if (!call_finally)
1332                 call_finally = arch_get_call_finally ();
1333
1334         if (ji) { /* we are inside managed code */
1335                 MonoMethod *m = ji->method;
1336                 int offset = 2;
1337
1338                 if (ji->num_clauses) {
1339                         int i;
1340
1341                         g_assert (ji->clauses);
1342                         
1343                         for (i = 0; i < ji->num_clauses; i++) {
1344                                 MonoJitExceptionInfo *ei = &ji->clauses [i];
1345
1346                                 if (ei->try_start <= ip && ip <= (ei->try_end)) { 
1347                                         /* catch block */
1348                                         if (ei->flags == 0 && mono_object_isinst (obj, 
1349                                                 mono_class_get (m->klass->image, ei->token_or_filter))) {
1350                                         
1351                                                 ctx->eip = (unsigned long)ei->handler_start;
1352                                                 ctx->ecx = (unsigned long)obj;
1353                                                 restore_context (ctx);
1354                                                 g_assert_not_reached ();
1355                                         }
1356                                 }
1357                         }
1358
1359                         /* no handler found - we need to call all finally handlers */
1360                         for (i = 0; i < ji->num_clauses; i++) {
1361                                 MonoJitExceptionInfo *ei = &ji->clauses [i];
1362
1363                                 if (ei->try_start <= ip && ip < (ei->try_end) &&
1364                                     (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
1365                                         call_finally (ctx, (unsigned long)ei->handler_start);
1366                                 }
1367                         }
1368                 }
1369
1370                 if (mono_object_isinst (obj, mono_defaults.exception_class)) {
1371                         char  *strace = mono_string_to_utf8 (((MonoException*)obj)->stack_trace);
1372                         char  *tmp;
1373
1374                         if (!strcmp (strace, "TODO: implement stack traces")){
1375                                 g_free (strace);
1376                                 strace = g_strdup ("");
1377                         }
1378
1379                         tmp = g_strdup_printf ("%sin %s.%s:%s ()\n", strace, m->klass->name_space,  
1380                                                m->klass->name, m->name);
1381
1382                         g_free (strace);
1383
1384                         ((MonoException*)obj)->stack_trace = mono_string_new (domain, tmp);
1385                         g_free (tmp);
1386                 }
1387
1388                 /* continue unwinding */
1389
1390                 /* restore caller saved registers */
1391                 if (ji->used_regs & X86_ESI_MASK) {
1392                         ctx->esi = *((int *)ctx->ebp + offset);
1393                         offset++;
1394                 }
1395                 if (ji->used_regs & X86_EDI_MASK) {
1396                         ctx->edi = *((int *)ctx->ebp + offset);
1397                         offset++;
1398                 }
1399                 if (ji->used_regs & X86_EBX_MASK) {
1400                         ctx->ebx = *((int *)ctx->ebp + offset);
1401                 }
1402
1403                 ctx->esp = ctx->ebp;
1404                 ctx->eip = *((int *)ctx->ebp + 1);
1405                 ctx->ebp = *((int *)ctx->ebp);
1406                 
1407                 if (ctx->ebp < (unsigned)mono_end_of_stack)
1408                         arch_handle_exception (ctx, obj);
1409                 else
1410                         mono_jit_abort (obj);
1411         } else {
1412                 gpointer *lmf_addr = TlsGetValue (lmf_thread_id);
1413                 MonoLMF *lmf;
1414                 MonoMethod *m;
1415
1416                 g_assert (lmf_addr);
1417                 lmf = *((MonoLMF **)lmf_addr);
1418
1419                 if (!lmf)
1420                         mono_jit_abort (obj);
1421
1422                 m = lmf->method;
1423
1424                 *lmf_addr = lmf->previous_lmf;
1425
1426                 ctx->esi = lmf->esi;
1427                 ctx->edi = lmf->edi;
1428                 ctx->ebx = lmf->ebx;
1429                 ctx->ebp = lmf->ebp;
1430                 ctx->eip = lmf->eip;
1431                 ctx->esp = (unsigned long)&lmf->eip;
1432
1433                 if (mono_object_isinst (obj, mono_defaults.exception_class)) {
1434                         char  *strace = mono_string_to_utf8 (((MonoException*)obj)->stack_trace);
1435                         char  *tmp;
1436
1437                         if (!strcmp (strace, "TODO: implement stack traces"))
1438                                 strace = g_strdup ("");
1439
1440                         tmp = g_strdup_printf ("%sin (unmanaged) %s.%s:%s ()\n", strace, m->klass->name_space,  
1441                                                m->klass->name, m->name);
1442
1443                         g_free (strace);
1444
1445                         ((MonoException*)obj)->stack_trace = mono_string_new (domain, tmp);
1446                         g_free (tmp);
1447                 }
1448
1449                 if (ctx->eip < (unsigned)mono_end_of_stack)
1450                         arch_handle_exception (ctx, obj);
1451                 else
1452                         mono_jit_abort (obj);
1453         }
1454
1455         g_assert_not_reached ();
1456 }
1457
1458 static void
1459 throw_exception (unsigned long eax, unsigned long ecx, unsigned long edx, unsigned long ebx,
1460                  unsigned long esi, unsigned long edi, unsigned long ebp, MonoObject *exc,
1461                  unsigned long eip,  unsigned long esp)
1462 {
1463         struct sigcontext ctx;
1464
1465         ctx.esp = esp;
1466         ctx.eip = eip;
1467         ctx.ebp = ebp;
1468         ctx.edi = edi;
1469         ctx.esi = esi;
1470         ctx.ebx = ebx;
1471         ctx.edx = edx;
1472         ctx.ecx = ecx;
1473         ctx.eax = eax;
1474         
1475         arch_handle_exception (&ctx, exc);
1476
1477         g_assert_not_reached ();
1478 }
1479
1480 /**
1481  * arch_get_throw_exception:
1482  *
1483  * Returns a function pointer which can be used to raise 
1484  * exceptions. The returned function has the following 
1485  * signature: void (*func) (MonoException *exc); 
1486  * For example to raise an arithmetic exception you can use:
1487  *
1488  * x86_push_imm (code, mono_get_exception_arithmetic ()); 
1489  * x86_call_code (code, arch_get_throw_exception ()); 
1490  *
1491  */
1492 gpointer 
1493 arch_get_throw_exception (void)
1494 {
1495         static guint8 start [24];
1496         static int inited = 0;
1497         guint8 *code;
1498
1499         if (inited)
1500                 return start;
1501
1502         inited = 1;
1503         code = start;
1504
1505         x86_push_reg (code, X86_ESP);
1506         x86_push_membase (code, X86_ESP, 4); /* IP */
1507         x86_push_membase (code, X86_ESP, 12); /* exception */
1508         x86_push_reg (code, X86_EBP);
1509         x86_push_reg (code, X86_EDI);
1510         x86_push_reg (code, X86_ESI);
1511         x86_push_reg (code, X86_EBX);
1512         x86_push_reg (code, X86_EDX);
1513         x86_push_reg (code, X86_ECX);
1514         x86_push_reg (code, X86_EAX);
1515         x86_call_code (code, throw_exception);
1516         /* we should never reach this breakpoint */
1517         x86_breakpoint (code);
1518
1519         g_assert ((code - start) < 24);
1520         return start;
1521 }
1522
1523 /**
1524  * arch_get_throw_exception_by_name:
1525  *
1526  * Returns a function pointer which can be used to raise 
1527  * corlib exceptions. The returned function has the following 
1528  * signature: void (*func) (char *exc_name); 
1529  * For example to raise an arithmetic exception you can use:
1530  *
1531  * x86_push_imm (code, "ArithmeticException"); 
1532  * x86_call_code (code, arch_get_throw_exception ()); 
1533  *
1534  */
1535 gpointer 
1536 arch_get_throw_exception_by_name ()
1537 {
1538         static guint8 start [32];
1539         static int inited = 0;
1540         guint8 *code;
1541
1542         if (inited)
1543                 return start;
1544
1545         inited = 1;
1546         code = start;
1547
1548         /* fixme: we do not save EAX, EDX, ECD - unsure if we need that */
1549
1550         x86_push_membase (code, X86_ESP, 4); /* exception name */
1551         x86_push_imm (code, "System");
1552         x86_push_imm (code, mono_defaults.exception_class->image);
1553         x86_call_code (code, mono_exception_from_name);
1554         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 12);
1555         /* save the newly create object (overwrite exception name)*/
1556         x86_mov_membase_reg (code, X86_ESP, 4, X86_EAX, 4);
1557         x86_jump_code (code, arch_get_throw_exception ());
1558
1559         g_assert ((code - start) < 32);
1560
1561         return start;
1562 }       
1563
1564 /*
1565  * this returns a helper method to invoke a method with a user supplied
1566  * stack frame. The returned method has the following signature:
1567  * invoke_method_with_frame ((gpointer code, gpointer frame, int frame_size);
1568  */
1569 static gpointer
1570 get_invoke_method_with_frame ()
1571 {
1572         static guint8 *start;
1573         guint8 *code;
1574
1575         if (start)
1576                 return start;
1577
1578         start = code = g_malloc (64);
1579
1580         /* Prolog */
1581         x86_push_reg (code, X86_EBP);
1582         x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
1583         x86_push_reg (code, X86_EBX);
1584         x86_push_reg (code, X86_EDI);
1585         x86_push_reg (code, X86_ESI);
1586
1587         x86_mov_reg_membase (code, X86_EAX, X86_EBP, 16, 4);
1588         x86_alu_reg_reg (code, X86_SUB, X86_ESP, X86_EAX);
1589
1590         x86_push_membase (code, X86_EBP, 16);
1591         x86_push_membase (code, X86_EBP, 12);
1592         x86_lea_membase (code, X86_EAX, X86_ESP, 2*4);
1593         x86_push_reg (code, X86_EAX);
1594         x86_call_code (code, memcpy);
1595         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 12);
1596
1597         x86_mov_reg_membase (code, X86_EAX, X86_EBP, 8, 4);
1598         x86_call_reg (code, X86_EAX);
1599
1600         x86_mov_reg_membase (code, X86_ECX, X86_EBP, 16, 4);
1601         x86_alu_reg_reg (code, X86_ADD, X86_ESP, X86_ECX);
1602
1603         /* Epilog */
1604         x86_pop_reg (code, X86_ESI);
1605         x86_pop_reg (code, X86_EDI);
1606         x86_pop_reg (code, X86_EBX);
1607         x86_leave (code);
1608         x86_ret (code);
1609         
1610         g_assert ((code - start) < 64);
1611
1612         return start;
1613 }
1614
1615 /**
1616  * arch_runtime_invoke:
1617  * @method: the method to invoke
1618  * @obj: this pointer
1619  * @params: array of parameter values.
1620  *
1621  * TODO: very ugly piece of code. we should replace that with a method-specific 
1622  * trampoline (as suggested by Paolo).
1623  */
1624 MonoObject*
1625 arch_runtime_invoke (MonoMethod *method, void *obj, void **params)
1626 {
1627         static guint64 (*invoke_int64) (gpointer code, gpointer frame, int frame_size) = NULL;
1628         static double (*invoke_double) (gpointer code, gpointer frame, int frame_size) = NULL;
1629         MonoObject *retval;
1630         MonoMethodSignature *sig = method->signature;
1631         int i, tmp, type, sp = 0;
1632         void *ret;
1633         int frame_size = 0;
1634         gpointer *frame;
1635         gpointer code;
1636
1637         /* allocate ret object. */
1638         if (sig->ret->type == MONO_TYPE_VOID) {
1639                 retval = NULL;
1640                 ret = NULL;
1641         } else {
1642                 MonoClass *klass = mono_class_from_mono_type (sig->ret);
1643                 if (klass->valuetype) {
1644                         retval = mono_object_new (mono_domain_get (), klass);
1645                         ret = ((char*)retval) + sizeof (MonoObject);
1646                 } else {
1647                         ret = &retval;
1648                 }
1649         }
1650    
1651         if (ISSTRUCT (sig->ret))
1652                 frame_size += sizeof (gpointer);
1653         
1654         if (sig->hasthis) 
1655                 frame_size += sizeof (gpointer);
1656
1657         for (i = 0; i < sig->param_count; ++i) {
1658                 int align;
1659                 frame_size += mono_type_stack_size (sig->params [i], &align);
1660         }
1661
1662         frame = alloca (frame_size);
1663
1664         if (ISSTRUCT (sig->ret))
1665                 frame [sp++] = ret;
1666
1667         if (sig->hasthis) 
1668                 frame [sp++] = obj;
1669                 
1670
1671         for (i = 0; i < sig->param_count; ++i) {
1672                 if (sig->params [i]->byref) {
1673                         frame [sp++] = params [i];
1674                         continue;
1675                 }
1676                 type = sig->params [i]->type;
1677 handle_enum:
1678                 switch (type) {
1679                 case MONO_TYPE_U1:
1680                 case MONO_TYPE_I1:
1681                 case MONO_TYPE_BOOLEAN:
1682                         tmp = *(MonoBoolean*)params [i];
1683                         frame [sp++] = (gpointer)tmp;                   
1684                         break;
1685                 case MONO_TYPE_U2:
1686                 case MONO_TYPE_I2:
1687                 case MONO_TYPE_CHAR:
1688                         tmp = *(gint16*)params [i];
1689                         frame [sp++] = (gpointer)tmp;                   
1690                         break;
1691 #if SIZEOF_VOID_P == 4
1692                 case MONO_TYPE_U:
1693                 case MONO_TYPE_I:
1694 #endif
1695                 case MONO_TYPE_U4:
1696                 case MONO_TYPE_I4:
1697                         frame [sp++] = (gpointer)*(gint32*)params [i];
1698                         break;
1699 #if SIZEOF_VOID_P == 8
1700                 case MONO_TYPE_U:
1701                 case MONO_TYPE_I:
1702 #endif
1703                 case MONO_TYPE_U8:
1704                 case MONO_TYPE_I8:
1705                         frame [sp++] = (gpointer)*(gint32*)params [i];
1706                         frame [sp++] = (gpointer)*(((gint32*)params [i]) + 1);
1707                         break;
1708                 case MONO_TYPE_VALUETYPE:
1709                         if (sig->params [i]->data.klass->enumtype) {
1710                                 type = sig->params [i]->data.klass->enum_basetype->type;
1711                                 goto handle_enum;
1712                         } else {
1713                                 g_warning ("generic valutype %s not handled in runtime invoke", sig->params [i]->data.klass->name);
1714                         }
1715                         break;
1716                 case MONO_TYPE_STRING:
1717                         frame [sp++] = params [i];
1718                         break;
1719                 default:
1720                         g_error ("type 0x%x not handled in invoke", sig->params [i]->type);
1721                 }
1722         }
1723
1724         code = arch_compile_method (method);
1725
1726         if (!invoke_int64)
1727                 invoke_int64 = (gpointer)invoke_double = get_invoke_method_with_frame ();
1728
1729         type = sig->ret->type;
1730 handle_enum_2:
1731         switch (type) {
1732         case MONO_TYPE_VOID:
1733                 invoke_int64 (code, frame, frame_size);         
1734                 break;
1735         case MONO_TYPE_U1:
1736         case MONO_TYPE_I1:
1737         case MONO_TYPE_BOOLEAN:
1738         case MONO_TYPE_U2:
1739         case MONO_TYPE_I2:
1740         case MONO_TYPE_CHAR:
1741 #if SIZEOF_VOID_P == 4
1742         case MONO_TYPE_U:
1743         case MONO_TYPE_I:
1744 #endif
1745         case MONO_TYPE_U4:
1746         case MONO_TYPE_I4:
1747         case MONO_TYPE_STRING:
1748                 *((guint32 *)ret) = invoke_int64 (code, frame, frame_size);             
1749                 break;
1750 #if SIZEOF_VOID_P == 8
1751         case MONO_TYPE_U:
1752         case MONO_TYPE_I:
1753 #endif
1754         case MONO_TYPE_U8:
1755         case MONO_TYPE_I8:
1756                 *((guint64 *)ret) = invoke_int64 (code, frame, frame_size);             
1757                 break;
1758         case MONO_TYPE_R4:
1759                 *((float *)ret) = invoke_double (code, frame, frame_size);              
1760                 break;
1761         case MONO_TYPE_R8:
1762                 *((double *)ret) = invoke_double (code, frame, frame_size);             
1763                 break;
1764         case MONO_TYPE_VALUETYPE:
1765                 if (sig->params [i]->data.klass->enumtype) {
1766                         type = sig->params [i]->data.klass->enum_basetype->type;
1767                         goto handle_enum_2;
1768                 } else 
1769                         invoke_int64 (code, frame, frame_size);         
1770                 break;
1771         default:
1772                 g_error ("type 0x%x not handled in invoke", sig->params [i]->type);
1773         }
1774
1775         return retval;
1776 }
1777
1778 gpointer
1779 arch_create_native_wrapper (MonoMethod *method)
1780 {
1781         MonoMethodSignature *csig = method->signature;
1782         MonoJitInfo *ji;
1783         guint8 *code, *start;
1784         int i, align, locals = 0, arg_size = 0;
1785         gboolean pinvoke = FALSE;
1786         GList *str_list = NULL;
1787
1788         if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
1789             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
1790                 pinvoke = TRUE;
1791
1792         /* compute the size of the activation frame */
1793
1794         if (csig->hasthis)
1795                 arg_size += sizeof (gpointer);
1796
1797         if (csig->ret->type == MONO_TYPE_VALUETYPE) {
1798                 g_assert (!csig->ret->byref);
1799                 arg_size += sizeof (gpointer);          
1800         }
1801                 
1802         for (i = 0; i < csig->param_count; ++i) {
1803                 arg_size += mono_type_stack_size (csig->params [i], &align);
1804                 if (pinvoke && (csig->params [i]->type == MONO_TYPE_STRING))
1805                         locals++;
1806         }
1807
1808         start = code = g_malloc (512);
1809
1810         /* save LMF - the instruction pointer is already on the 
1811          * stack (return address) */
1812
1813         /* save all caller saved regs */
1814         x86_push_reg (code, X86_EBX);
1815         x86_push_reg (code, X86_EDI);
1816         x86_push_reg (code, X86_ESI);
1817         x86_push_reg (code, X86_EBP);
1818
1819         /* save method info */
1820         x86_push_imm (code, method);
1821         
1822         /* get the address of lmf for the current thread */
1823         x86_call_code (code, arch_get_lmf_addr);
1824         /* push lmf */
1825         x86_push_reg (code, X86_EAX); 
1826         /* push *lfm (previous_lmf) */
1827         x86_push_membase (code, X86_EAX, 0);
1828         /* *(lmf) = ESP */
1829         x86_mov_membase_reg (code, X86_EAX, 0, X86_ESP, 4);
1830
1831         if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1832                 guint8 *l1, *l2;
1833
1834                 if (arg_size) {
1835                         /* repush all arguments */
1836                         /* load argument size -4 into ECX */
1837                         x86_mov_reg_imm (code, X86_ECX, (arg_size - 4));
1838                         /* load source address */
1839                         x86_lea_membase (code, X86_ESI, X86_ESP, sizeof (MonoLMF));
1840                         /* allocate destination */
1841                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, arg_size);
1842                         /* load destination address */
1843                         x86_mov_reg_reg (code, X86_EDI, X86_ESP, 4);
1844
1845                         l1 = code;
1846                         x86_mov_reg_memindex (code, X86_EAX, X86_ESI, 0, X86_ECX, 0, 4);
1847                         x86_mov_memindex_reg (code, X86_EDI, 0, X86_ECX, 0, X86_EAX, 4);
1848                         x86_alu_reg_imm (code, X86_SUB, X86_ECX, 4);
1849                         l2 = code;
1850                         x86_branch8 (code, X86_CC_GEZ, l1 - (l2 + 2), FALSE); 
1851                 }
1852
1853         } else if (pinvoke) {
1854                 int offset = arg_size + (locals <<2) + sizeof (MonoLMF) - 4;
1855                 int l = 0;
1856                 
1857                 /* allocate locals */
1858                 if (locals) {
1859                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, (locals<<2));
1860                         x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
1861                 }
1862
1863                 for (i = csig->param_count - 1; i >= 0; i--) {
1864                         MonoType *t = csig->params [i];
1865                         int type;
1866
1867                         if (t->byref) {
1868                                 x86_push_membase (code, X86_ESP, offset);
1869                                 continue;
1870                         }
1871
1872                         type = t->type;
1873 enum_marshal:
1874                         switch (type) {
1875                         case MONO_TYPE_BOOLEAN:
1876                         case MONO_TYPE_CHAR:
1877                         case MONO_TYPE_I1:
1878                         case MONO_TYPE_U1:
1879                         case MONO_TYPE_I2:
1880                         case MONO_TYPE_U2:
1881                         case MONO_TYPE_I4:
1882                         case MONO_TYPE_U4:
1883                         case MONO_TYPE_I:
1884                         case MONO_TYPE_U:
1885                         case MONO_TYPE_OBJECT:
1886                         case MONO_TYPE_CLASS:
1887                         case MONO_TYPE_SZARRAY:
1888                         case MONO_TYPE_PTR:
1889                         case MONO_TYPE_FNPTR:
1890                         case MONO_TYPE_ARRAY:
1891                         case MONO_TYPE_TYPEDBYREF:
1892                         case MONO_TYPE_R4:
1893                                 x86_push_membase (code, X86_ESP, offset);
1894                                 break;
1895                         case MONO_TYPE_STRING:
1896                                 x86_push_membase (code, X86_ESP, offset);
1897                                 x86_call_code (code, mono_string_to_utf8);
1898                                 x86_mov_membase_reg (code, X86_ESP, 0, X86_EAX, 4);
1899                                 str_list = g_list_prepend (str_list, (gpointer)l);
1900                                 x86_mov_membase_reg (code, X86_EBP, l, X86_EAX, 4);
1901                                 l+= 4;
1902                                 break;
1903                         case MONO_TYPE_I8:
1904                         case MONO_TYPE_U8:
1905                         case MONO_TYPE_R8:
1906                                 x86_push_membase (code, X86_ESP, offset);
1907                                 x86_push_membase (code, X86_ESP, offset);
1908                                 break;
1909                         case MONO_TYPE_VALUETYPE:
1910                                 if (t->data.klass->enumtype) {
1911                                         type = t->data.klass->enum_basetype->type;
1912                                         goto enum_marshal;
1913                                 } else {
1914                                         int j, size;
1915                                         size = mono_type_stack_size (csig->params [i], &align);
1916                                         size = size >> 2;
1917                                         for (j = 0; j < size; j++)
1918                                                 x86_push_membase (code, X86_ESP, offset);
1919                                 }
1920                                 break;
1921                         default:
1922                                 g_error ("type 0x%02x unknown", t->type);
1923
1924                         }
1925                 }                       
1926
1927                 if (csig->ret->type == MONO_TYPE_VALUETYPE) {
1928                         g_assert (!csig->ret->byref);
1929                         x86_push_membase (code, X86_ESP, offset);
1930                 }
1931
1932                 if (csig->hasthis) {
1933                         x86_push_membase (code, X86_ESP, offset);
1934                 }
1935
1936         } else {
1937                 g_assert_not_reached ();
1938         }
1939
1940         if (method->addr) {
1941                 /* call the native code */
1942                 x86_call_code (code, method->addr);
1943         } else {
1944                 /* raise exception */
1945                 x86_push_imm (code, "NotImplementedException");              
1946                 x86_call_code (code, arch_get_throw_exception_by_name ());
1947         }
1948
1949         /* free pinvoke string args */
1950         if (str_list) {
1951                 GList *l;
1952
1953                 x86_push_reg (code, X86_EAX);
1954                 x86_push_reg (code, X86_EDX);
1955                 
1956                 for (l = str_list; l; l = l->next) {
1957                         x86_push_membase (code, X86_EBP, ((int)l->data));
1958                         x86_call_code (code, g_free);
1959                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
1960                 }
1961
1962                 x86_pop_reg (code, X86_EDX);
1963                 x86_pop_reg (code, X86_EAX);
1964
1965                 g_list_free (str_list);
1966         }
1967
1968         /* remove arguments from stack */
1969         if (arg_size || locals)
1970                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, arg_size + (locals<<2));
1971
1972         if (pinvoke && !csig->ret->byref && (csig->ret->type == MONO_TYPE_STRING)) {
1973                 /* If the argument is non-null, then convert the value back */
1974                 x86_alu_reg_reg (code, X86_OR, X86_EAX, X86_EAX);
1975                 x86_branch8 (code, X86_CC_EQ, 9, FALSE);
1976                 x86_push_reg (code, X86_EAX);
1977                 x86_call_code (code, mono_string_new_wrapper);
1978                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
1979         }
1980         
1981         /* restore the LMF */
1982         
1983         /* ebx = previous_lmf */
1984         x86_pop_reg (code, X86_EBX);
1985         /* edi = lmf */
1986         x86_pop_reg (code, X86_EDI);
1987         /* *(lmf) = previous_lmf */
1988         x86_mov_membase_reg (code, X86_EDI, 0, X86_EBX, 4);
1989
1990         /* discard method info */
1991         x86_pop_reg (code, X86_ESI);
1992
1993         /* restore caller saved regs */
1994         x86_pop_reg (code, X86_EBP);
1995         x86_pop_reg (code, X86_ESI);
1996         x86_pop_reg (code, X86_EDI);
1997         x86_pop_reg (code, X86_EBX);
1998
1999         x86_ret (code);
2000
2001         /* we store a dummy jit info (code size 4), so that mono_delegate_ctor
2002          * is able to find a method info for icalls and pinvoke methods */
2003         ji = mono_mempool_alloc0 (mono_root_domain->mp, sizeof (MonoJitInfo));
2004         ji->method = method;
2005         ji->code_start = start;
2006         ji->code_size = 4;
2007         ji->used_regs = 0;
2008         ji->num_clauses = 0;
2009         mono_jit_info_table_add (mono_root_domain, ji);
2010
2011         g_assert ((code - start) < 512);
2012
2013         return start;
2014 }
2015
2016