1227b51024f01592e559f39767b9625df7eb9246
[mono.git] / mono / arch / ppc / tramp.c
1 /*
2  * Create trampolines to invoke arbitrary functions.
3  * 
4  * Copyright (C) Radek Doulik
5  * 
6  */
7
8 #include "config.h"
9 #include <stdlib.h>
10 #include "ppc-codegen.h"
11 #include "mono/metadata/class.h"
12 #include "mono/metadata/tabledefs.h"
13 #include "mono/interpreter/interp.h"
14 #include "mono/metadata/appdomain.h"
15
16 #ifdef NEED_MPROTECT
17 #include <sys/mman.h>
18 #include <limits.h>    /* for PAGESIZE */
19 #ifndef PAGESIZE
20 #define PAGESIZE 4096
21 #endif
22 #endif
23
24 #define DEBUG(x) x
25
26 /* gpointer
27 fake_func (gpointer (*callme)(gpointer), stackval *retval, void *this_obj, stackval *arguments)
28 {
29         guint32 i = 0xc002becd;
30
31         callme = (gpointer) 0x100fabcd;
32
33         *(gpointer*)retval = (gpointer)(*callme) (arguments [0].data.p, arguments [1].data.p, arguments [2].data.p);
34         *(gdouble*) retval = (gdouble)(*callme) (arguments [0].data.f);
35
36         return (gpointer) (*callme) (((MonoType *)arguments [0]. data.p)->data.klass);
37 } */
38
39 #define MIN_CACHE_LINE 8
40
41 static void inline
42 flush_icache (guint8 *code, guint size)
43 {
44         guint i;
45         guint8 *p;
46
47         p = code;
48         for (i = 0; i < size; i += MIN_CACHE_LINE, p += MIN_CACHE_LINE) {
49                 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
50         }
51         asm ("sync");
52         p = code;
53         for (i = 0; i < size; i += MIN_CACHE_LINE, p += MIN_CACHE_LINE) {
54                 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
55         }
56         asm ("sync");
57         asm ("isync");
58 }
59
60 #define NOT_IMPLEMENTED(x) \
61                 g_error ("FIXME: %s is not yet implemented. (trampoline)", x);
62
63 #define PROLOG_INS 8
64 #define CALL_INS   2
65 #define EPILOG_INS 6
66 #define MINIMAL_STACK_SIZE 5
67 #define FLOAT_REGS 8
68 #define GENERAL_REGS 8
69
70 static void inline
71 add_general (guint *gr, guint *stack_size, guint *code_size, gboolean simple)
72 {
73         if (simple) {
74                 if (*gr >= GENERAL_REGS) {
75                         *stack_size += 4;
76                         *code_size += 8;    /* load from stack, save on stack */
77                 } else {
78                         *code_size += 4;    /* load from stack */
79                 }
80         } else {
81                 if (*gr >= GENERAL_REGS - 1) {
82                         *stack_size += 8 + (*stack_size % 8);
83                         *code_size += 16;   /* 2x load from stack, 2x save to stack */
84                 } else {
85                         *code_size += 16;   /* 2x load from stack */
86                 }
87                 if ((*gr) && 1)
88                         (*gr) ++;
89                 (*gr) ++;
90         }
91         (*gr) ++;
92 }
93
94 static void inline
95 calculate_sizes (MonoMethodSignature *sig, guint *stack_size, guint *code_size, gboolean string_ctor)
96 {
97         guint i, fr, gr;
98         guint32 simpletype;
99
100         fr = gr = 0;
101         *stack_size = MINIMAL_STACK_SIZE*4;
102         *code_size  = (PROLOG_INS + CALL_INS + EPILOG_INS)*4;
103
104         if (sig->hasthis) {
105                 add_general (&gr, stack_size, code_size, TRUE);
106         }
107
108         for (i = 0; i < sig->param_count; ++i) {
109                 if (sig->params [i]->byref) {
110                         add_general (&gr, stack_size, code_size, TRUE);
111                         continue;
112                 }
113                 simpletype = sig->params [i]->type;
114         enum_calc_size:
115                 switch (simpletype) {
116                 case MONO_TYPE_BOOLEAN:
117                 case MONO_TYPE_CHAR:
118                 case MONO_TYPE_I1:
119                 case MONO_TYPE_U1:
120                 case MONO_TYPE_I2:
121                 case MONO_TYPE_U2:
122                 case MONO_TYPE_I4:
123                 case MONO_TYPE_U4:
124                 case MONO_TYPE_I:
125                 case MONO_TYPE_U:
126                 case MONO_TYPE_PTR:
127                 case MONO_TYPE_CLASS:
128                 case MONO_TYPE_OBJECT:
129                 case MONO_TYPE_STRING:
130                         add_general (&gr, stack_size, code_size, TRUE);
131                         break;
132                 case MONO_TYPE_SZARRAY:
133                         add_general (&gr, stack_size, code_size, TRUE);
134                         *code_size += 4;
135                         break;
136                 case MONO_TYPE_VALUETYPE:
137                         if (sig->params [i]->data.klass->enumtype) {
138                                 simpletype = sig->params [i]->data.klass->enum_basetype->type;
139                                 goto enum_calc_size;
140                         }
141                         if (mono_class_value_size (sig->params [i]->data.klass, NULL) != 4)
142                                 g_error ("can only marshal enums, not generic structures (size: %d)",
143                                          mono_class_value_size (sig->params [i]->data.klass, NULL));
144                         add_general (&gr, stack_size, code_size, TRUE);
145                         *code_size += 4;
146                         break;
147                 case MONO_TYPE_I8:
148                         add_general (&gr, stack_size, code_size, FALSE);
149                         break;
150                 case MONO_TYPE_R4:
151                 case MONO_TYPE_R8:
152                         if (fr < 7) {
153                                 *code_size += 4;
154                                 fr ++;
155                         } else {
156                                 NOT_IMPLEMENTED ("R8 arg");
157                         }
158                         break;
159                 default:
160                         g_error ("Can't trampoline 0x%x", sig->params [i]->type);
161                 }
162         }
163
164         if (sig->ret->byref || string_ctor) {
165                 *code_size += 8;
166         } else {
167                 simpletype = sig->ret->type;
168 enum_retvalue:
169                 switch (simpletype) {
170                 case MONO_TYPE_BOOLEAN:
171                 case MONO_TYPE_I1:
172                 case MONO_TYPE_U1:
173                 case MONO_TYPE_I2:
174                 case MONO_TYPE_U2:
175                 case MONO_TYPE_CHAR:
176                 case MONO_TYPE_I4:
177                 case MONO_TYPE_U4:
178                 case MONO_TYPE_I:
179                 case MONO_TYPE_U:
180                 case MONO_TYPE_CLASS:
181                 case MONO_TYPE_OBJECT:
182                 case MONO_TYPE_R4:
183                 case MONO_TYPE_R8:
184                 case MONO_TYPE_SZARRAY:
185                 case MONO_TYPE_ARRAY:
186                 case MONO_TYPE_STRING:
187                         *code_size += 8;
188                         break;
189                 case MONO_TYPE_I8:
190                         *code_size += 12;
191                         break;
192                 case MONO_TYPE_VALUETYPE:
193                         if (sig->ret->data.klass->enumtype) {
194                                 simpletype = sig->ret->data.klass->enum_basetype->type;
195                                 goto enum_retvalue;
196                         }
197                         NOT_IMPLEMENTED ("valuetype");
198                         break;
199                 case MONO_TYPE_VOID:
200                         break;
201                 default:
202                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
203                 }
204         }
205
206         /* align stack size to 16 */
207         DEBUG (printf ("      stack size: %d (%d)\n       code size: %d\n", (*stack_size + 15) & ~15, *stack_size, *code_size));
208         *stack_size = (*stack_size + 15) & ~15;
209
210 }
211
212 static inline guint8 *
213 emit_prolog (guint8 *p, MonoMethodSignature *sig, guint stack_size)
214 {
215         /* function prolog */
216         ppc_stwu (p, ppc_r1, -stack_size, ppc_r1);     /* sp      <--- sp - stack_size, sp[0] <---- sp save sp, alloc stack */
217         ppc_mflr (p, ppc_r0);                          /* r0      <--- LR */
218         ppc_stw  (p, ppc_r31, stack_size - 4, ppc_r1); /* sp[+4]  <--- r31     save r31 */
219         ppc_stw  (p, ppc_r0, stack_size + 4, ppc_r1);  /* sp[-4]  <--- LR      save return address for "callme" */
220         ppc_mr   (p, ppc_r31, ppc_r1);                 /* r31     <--- sp */
221
222         ppc_mr   (p, ppc_r12, ppc_r6);                        /* keep "arguments" in register */
223         ppc_mr   (p, ppc_r0, ppc_r3);                         /* keep "callme" in register */
224
225         ppc_stw  (p, ppc_r4, stack_size - 12, ppc_r31);               /* preserve "retval", sp[+8] */
226
227         return p;
228 }
229
230 #define ARG_BASE ppc_r12
231 #define SAVE_4_IN_GENERIC_REGISTER \
232                         if (gr < GENERAL_REGS) { \
233                                 ppc_lwz  (p, ppc_r3 + gr, i*16, ARG_BASE); \
234                                 gr ++; \
235                         } else { \
236                                 ppc_lwz  (p, ppc_r11, i*16, ARG_BASE); \
237                                 ppc_stw  (p, ppc_r11, stack_par_pos, ppc_r1); \
238                                 stack_par_pos += 4; \
239                         }
240
241 inline static guint8*
242 emit_save_parameters (guint8 *p, MonoMethodSignature *sig, guint stack_size)
243 {
244         guint i, fr, gr, act_strs, stack_par_pos;
245         guint32 simpletype;
246
247         fr = gr = 0;
248         act_strs = 0;
249         stack_par_pos = 8;
250
251         if (sig->hasthis) {
252                 ppc_mr (p, ppc_r3, ppc_r5);
253                 gr ++;
254         }
255
256         act_strs = 0;
257         for (i = 0; i < sig->param_count; ++i) {
258                 if (sig->params [i]->byref) {
259                         SAVE_4_IN_GENERIC_REGISTER;
260                         continue;
261                 }
262                 simpletype = sig->params [i]->type;
263         enum_calc_size:
264                 switch (simpletype) {
265                 case MONO_TYPE_BOOLEAN:
266                 case MONO_TYPE_I1:
267                 case MONO_TYPE_U1:
268                 case MONO_TYPE_I2:
269                 case MONO_TYPE_U2:
270                 case MONO_TYPE_CHAR:
271                 case MONO_TYPE_I4:
272                 case MONO_TYPE_U4:
273                 case MONO_TYPE_I:
274                 case MONO_TYPE_U:
275                 case MONO_TYPE_PTR:
276                 case MONO_TYPE_CLASS:
277                 case MONO_TYPE_OBJECT:
278                 case MONO_TYPE_STRING:
279                 case MONO_TYPE_SZARRAY:
280                         SAVE_4_IN_GENERIC_REGISTER;
281                         break;
282                         /* g_warning ("untested marshaling\n");
283                                 if (gr < GENERAL_REGS) {
284                                         ppc_lwz  (p, ppc_r3 + gr, i*16, ARG_BASE);
285                                         ppc_lwz  (p, ppc_r3 + gr, G_STRUCT_OFFSET (MonoArray, vector), ppc_r3 + gr);
286                                         gr ++;
287                                 } else {
288                                         NOT_IMPLEMENTED ("save marshalled SZARRAY on stack");
289                                 }
290                                 break; */
291                 case MONO_TYPE_VALUETYPE:
292                         if (sig->params [i]->data.klass->enumtype) {
293                                 simpletype = sig->params [i]->data.klass->enum_basetype->type;
294                                 goto enum_calc_size;
295                         }
296                         if (mono_class_value_size (sig->params [i]->data.klass, NULL) != 4)
297                                 g_error ("can only marshal enums, not generic structures (size: %d)",
298                                          mono_class_value_size (sig->params [i]->data.klass, NULL));
299                         if (gr < GENERAL_REGS) {
300                                 ppc_lwz  (p, ppc_r3 + gr, i*16, ARG_BASE);
301                                 ppc_lwz  (p, ppc_r3 + gr, 0, ppc_r3 + gr);
302                                 gr ++;
303                         } else {
304                                 NOT_IMPLEMENTED ("save value type on stack");
305                         }
306                         break;
307                 case MONO_TYPE_I8:
308                         if (gr < 7) {
309                                 if (gr & 1)
310                                         gr ++;
311                                 ppc_lwz  (p, ppc_r3 + gr, i*16, ARG_BASE);
312                                 gr ++;
313                                 ppc_lwz  (p, ppc_r3 + gr, i*16 + 4, ARG_BASE);
314                                 gr ++;
315                         } else {
316                                 NOT_IMPLEMENTED ("i8 on stack");
317                         }
318                         break;
319                 case MONO_TYPE_R4:
320                         if (fr < 7) {
321                                 ppc_lfs  (p, ppc_f1 + fr, i*16, ARG_BASE);
322                                 fr ++;
323                         } else {
324                                 NOT_IMPLEMENTED ("r4 on stack");
325                         }
326                         break;
327                 case MONO_TYPE_R8:
328                         if (fr < 7) {
329                                 ppc_lfd  (p, ppc_f1 + fr, i*16, ARG_BASE);
330                                 fr ++;
331                         } else {
332                                 NOT_IMPLEMENTED ("r8 on stack");
333                         }
334                         break;
335                 default:
336                         g_error ("Can't trampoline 0x%x", sig->params [i]->type);
337                 }
338         }
339
340         return p;
341 }
342
343 static inline guint8 *
344 alloc_code_memory (guint code_size)
345 {
346         guint8 *p;
347
348 #ifdef NEED_MPROTECT
349         p = g_malloc (code_size + PAGESIZE - 1);
350
351         /* Align to a multiple of PAGESIZE, assumed to be a power of two */
352         p = (char *)(((int) p + PAGESIZE-1) & ~(PAGESIZE-1));
353 #else
354         p = g_malloc (code_size);
355 #endif
356         DEBUG (printf ("           align: %p (%d)\n", p, (guint)p % 4));
357
358         return p;
359 }
360
361 /* static MonoString*
362 mono_string_new_wrapper (const char *text)
363 {
364         return text ? mono_string_new (mono_domain_get (), text) : NULL;
365 } */
366
367 static inline guint8 *
368 emit_call_and_store_retval (guint8 *p, MonoMethodSignature *sig, guint stack_size, gboolean string_ctor)
369 {
370         guint32 simpletype;
371
372         /* call "callme" */
373         ppc_mtlr (p, ppc_r0);
374         ppc_blrl (p);
375
376         /* get return value */
377         if (sig->ret->byref || string_ctor) {
378                 ppc_lwz  (p, ppc_r9, stack_size - 12, ppc_r31);        /* load "retval" address */
379                 ppc_stw  (p, ppc_r3, 0, ppc_r9);                       /* save return value (r3) to "retval" */
380         } else {
381                 simpletype = sig->ret->type;
382 enum_retvalue:
383                 switch (simpletype) {
384                 case MONO_TYPE_BOOLEAN:
385                 case MONO_TYPE_I1:
386                 case MONO_TYPE_U1:
387                         ppc_lwz  (p, ppc_r9, stack_size - 12, ppc_r31);        /* load "retval" address */
388                         ppc_stb  (p, ppc_r3, 0, ppc_r9);                       /* save return value (r3) to "retval" */
389                         break;
390                 case MONO_TYPE_I2:
391                 case MONO_TYPE_U2:
392                 case MONO_TYPE_CHAR:
393                         ppc_lwz  (p, ppc_r9, stack_size - 12, ppc_r31);        /* load "retval" address */
394                         ppc_sth  (p, ppc_r3, 0, ppc_r9);                       /* save return value (r3) to "retval" */
395                         break;
396                 case MONO_TYPE_I4:
397                 case MONO_TYPE_U4:
398                 case MONO_TYPE_I:
399                 case MONO_TYPE_U:
400                 case MONO_TYPE_CLASS:
401                 case MONO_TYPE_OBJECT:
402                 case MONO_TYPE_SZARRAY:
403                 case MONO_TYPE_ARRAY:
404                 case MONO_TYPE_STRING:
405                         ppc_lwz  (p, ppc_r9, stack_size - 12, ppc_r31);        /* load "retval" address */
406                         ppc_stw  (p, ppc_r3, 0, ppc_r9);                       /* save return value (r3) to "retval" */
407                         break;
408                 case MONO_TYPE_R4:
409                         ppc_lwz  (p, ppc_r9, stack_size - 12, ppc_r31);        /* load "retval" address */
410                         ppc_stfs (p, ppc_f1, 0, ppc_r9);                       /* save return value (f1) to "retval" */
411                         break;
412                 case MONO_TYPE_R8:
413                         ppc_lwz  (p, ppc_r9, stack_size - 12, ppc_r31);        /* load "retval" address */
414                         ppc_stfd (p, ppc_f1, 0, ppc_r9);                       /* save return value (f1) to "retval" */
415                         break;
416                 case MONO_TYPE_I8:
417                         ppc_lwz  (p, ppc_r9, stack_size - 12, ppc_r31);        /* load "retval" address */
418                         ppc_stw  (p, ppc_r3, 0, ppc_r9);                       /* save return value (r3) to "retval" */
419                         ppc_stw  (p, ppc_r4, 4, ppc_r9);                       /* save return value (r3) to "retval" */
420                         break;
421                 case MONO_TYPE_VALUETYPE:
422                         if (sig->ret->data.klass->enumtype) {
423                                 simpletype = sig->ret->data.klass->enum_basetype->type;
424                                 goto enum_retvalue;
425                         }
426                         NOT_IMPLEMENTED ("retval valuetype");
427                         break;
428                 case MONO_TYPE_VOID:
429                         break;
430                 default:
431                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
432                 }
433         }
434
435         return p;
436 }
437
438 static inline guint8 *
439 emit_epilog (guint8 *p, MonoMethodSignature *sig, guint stack_size)
440 {
441         /* function epilog */
442         ppc_lwz  (p, ppc_r11, 0,  ppc_r1);        /* r11     <--- sp[0]   load backchain from caller's function */
443         ppc_lwz  (p, ppc_r0, 4, ppc_r11);         /* r0      <--- r11[4]  load return address */
444         ppc_mtlr (p, ppc_r0);                     /* LR      <--- r0      set return address */
445         ppc_lwz  (p, ppc_r31, -4, ppc_r11);       /* r31     <--- r11[-4] restore r31 */
446         ppc_mr   (p, ppc_r1, ppc_r11);            /* sp      <--- r11     restore stack */
447         ppc_blr  (p);                             /* return */
448
449         return p;
450 }
451
452 MonoPIFunc
453 mono_create_trampoline (MonoMethodSignature *sig, gboolean string_ctor)
454 {
455         guint8 *p, *code_buffer;
456         guint stack_size, code_size;
457
458         DEBUG (printf ("\nPInvoke [start emiting]\n"));
459         calculate_sizes (sig, &stack_size, &code_size, string_ctor);
460
461         p = code_buffer = alloc_code_memory (code_size);
462         p = emit_prolog (p, sig, stack_size);
463         p = emit_save_parameters (p, sig, stack_size);
464         p = emit_call_and_store_retval (p, sig, stack_size, string_ctor);
465         p = emit_epilog (p, sig, stack_size);
466
467         /* {
468                 guchar *cp;
469                 printf (".text\n.align 4\n.globl main\n.type main,@function\nmain:\n");
470                 for (cp = code_buffer; cp < p; cp++) {
471                         printf (".byte 0x%x\n", *cp);
472                 }
473                 } */
474
475 #ifdef NEED_MPROTECT
476         if (mprotect (code_buffer, 1024, PROT_READ | PROT_WRITE | PROT_EXEC)) {
477                 g_error ("Cannot mprotect trampoline\n");
478         }
479 #endif
480
481         DEBUG (printf ("emited code size: %d\n", p - code_buffer));
482         flush_icache (code_buffer, p - code_buffer);
483
484         DEBUG (printf ("PInvoke [end emiting]\n"));
485
486         return (MonoPIFunc) code_buffer;
487         /* return fake_func; */
488 }
489
490
491 #define MINV_POS  8   /* MonoInvocation structure offset on stack */
492 #define STACK_POS (MINV_POS - sizeof (stackval) * sig->param_count)
493 #define OBJ_POS   8
494 #define TYPE_OFFSET (G_STRUCT_OFFSET (stackval, type))
495
496 /*
497  * Returns a pointer to a native function that can be used to
498  * call the specified method.
499  * The function created will receive the arguments according
500  * to the call convention specified in the method.
501  * This function works by creating a MonoInvocation structure,
502  * filling the fields in and calling ves_exec_method on it.
503  * Still need to figure out how to handle the exception stuff
504  * across the managed/unmanaged boundary.
505  */
506 void *
507 mono_create_method_pointer (MonoMethod *method)
508 {
509         MonoMethodSignature *sig;
510         MonoJitInfo *ji;
511         guint8 *p, *code_buffer;
512         guint i, code_size, stack_size, stackval_arg_pos, local_pos, local_start, reg_param, stack_param;
513         guint32 simpletype;
514
515         code_size = 1024;
516         stack_size = 1024;
517         stack_param = 0;
518
519         sig = method->signature;
520
521         p = code_buffer = g_malloc (code_size);
522
523         DEBUG (printf ("\nDelegate [start emiting] %s\n", method->name));
524
525         /* prolog */
526         ppc_stwu (p, ppc_r1, -stack_size, ppc_r1);     /* sp      <--- sp - stack_size, sp[0] <---- sp save sp, alloc stack */
527         ppc_mflr (p, ppc_r0);                          /* r0      <--- LR */
528         ppc_stw  (p, ppc_r31, stack_size - 4, ppc_r1); /* sp[+4]  <--- r31     save r31 */
529         ppc_stw  (p, ppc_r0, stack_size + 4, ppc_r1);  /* sp[-4]  <--- LR      save return address for "callme" */
530         ppc_mr   (p, ppc_r31, ppc_r1);                 /* r31     <--- sp */
531
532         /* let's fill MonoInvocation */
533         /* first zero some fields */
534         ppc_li   (p, ppc_r0, 0);
535         ppc_stw  (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex)), ppc_r31);
536         ppc_stw  (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex_handler)), ppc_r31);
537         ppc_stw  (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, child)), ppc_r31);
538         ppc_stw  (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, parent)), ppc_r31);
539
540         /* set method pointer */
541         ppc_lis  (p, ppc_r0,     (guint32) method >> 16);
542         ppc_ori  (p, ppc_r0, ppc_r0, (guint32) method & 0xffff);
543         ppc_stw  (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, method)), ppc_r31);
544
545         local_start = local_pos = MINV_POS + sizeof (MonoInvocation) + (sig->param_count + 1) * sizeof (stackval);
546
547         if (sig->hasthis) {
548                 ppc_stw  (p, ppc_r3, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj)), ppc_r31);
549                 reg_param = 1;
550         } else {
551                 ppc_stw  (p, ppc_r3, local_pos, ppc_r31);
552                 local_pos += 4;
553                 reg_param = 0;
554         }
555         ppc_stw (p, ppc_r4, local_pos, ppc_r31); local_pos += 4;
556         ppc_stw (p, ppc_r5, local_pos, ppc_r31); local_pos += 4;
557
558         /* set MonoInvocation::stack_args */
559         stackval_arg_pos = MINV_POS + sizeof (MonoInvocation);
560         ppc_addi (p, ppc_r0, ppc_r31, stackval_arg_pos);
561         ppc_stw  (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, stack_args)), ppc_r31);
562
563         /* add stackval arguments */
564         for (i = 0; i < sig->param_count; ++i) {
565 #define CALL_STACKVAL_FROM_DATA \
566                 ppc_lis  (p, ppc_r0, (guint32) stackval_from_data >> 16); \
567                 ppc_ori  (p, ppc_r0, ppc_r0, (guint32) stackval_from_data & 0xffff); \
568                 ppc_mtlr (p, ppc_r0); \
569                 ppc_blrl (p)
570 #define CALL_SIZE_4 \
571                         if (reg_param < 3 - (sig->hasthis ? 1 : 0)) { \
572                                 ppc_addi (p, ppc_r5, ppc_r31, local_start + (reg_param - (sig->hasthis ? 1 : 0))*4); \
573                                 reg_param ++; \
574                         } else if (reg_param < 8) { \
575                                 ppc_stw  (p, ppc_r3 + reg_param, local_pos, ppc_r31); \
576                                 ppc_addi (p, ppc_r5, ppc_r31, local_pos); \
577                                 reg_param ++; \
578                         } else { \
579                                 ppc_addi (p, ppc_r5, stack_size + 8 + stack_param, ppc_r31); \
580                                 stack_param ++; \
581                         } \
582                         ppc_lis  (p, ppc_r3, (guint32) sig->params [i] >> 16); \
583                         ppc_addi (p, ppc_r4, ppc_r31, stackval_arg_pos); \
584                         stackval_arg_pos ++; \
585                         ppc_ori  (p, ppc_r3, ppc_r3, (guint32) sig->params [i] & 0xffff); \
586 \
587                         CALL_STACKVAL_FROM_DATA
588
589                 if (sig->params [i]->byref) {
590                         CALL_SIZE_4;
591                         continue;
592                 }
593                 simpletype = sig->params [i]->type;
594         enum_calc_size:
595                 switch (simpletype) {
596                 case MONO_TYPE_BOOLEAN:
597                 case MONO_TYPE_I1:
598                 case MONO_TYPE_U1:
599                 case MONO_TYPE_I2:
600                 case MONO_TYPE_U2:
601                 case MONO_TYPE_CHAR:
602                 case MONO_TYPE_I4:
603                 case MONO_TYPE_U4:
604                 case MONO_TYPE_I:
605                 case MONO_TYPE_U:
606                 case MONO_TYPE_PTR:
607                 case MONO_TYPE_SZARRAY:
608                 case MONO_TYPE_CLASS:
609                 case MONO_TYPE_OBJECT:
610                 case MONO_TYPE_STRING:
611                         CALL_SIZE_4;
612                         break;
613                 case MONO_TYPE_VALUETYPE:
614                         NOT_IMPLEMENTED ("value type");
615                         break;
616                 case MONO_TYPE_I8:
617                         NOT_IMPLEMENTED ("i8");
618                         break;
619                 case MONO_TYPE_R4:
620                         NOT_IMPLEMENTED ("r4");
621                         break;
622                 case MONO_TYPE_R8:
623                         NOT_IMPLEMENTED ("r8");
624                         break;
625                 default:
626                         g_error ("Can't delegate 0x%x type", sig->params [i]->type);
627                 }
628         }
629
630         /* return value storage */
631         if (sig->param_count) {
632                 ppc_addi (p, ppc_r0, ppc_r31, stackval_arg_pos);
633         }
634         ppc_stw  (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, retval)), ppc_r31);
635
636         /* call ves_exec_method */
637         ppc_lis  (p, ppc_r0,     (guint32) ves_exec_method >> 16);
638         ppc_addi (p, ppc_r3, ppc_r31, MINV_POS);
639         ppc_ori  (p, ppc_r0, ppc_r0, (guint32) ves_exec_method & 0xffff);
640         ppc_mtlr (p, ppc_r0);
641         ppc_blrl (p);
642
643         /* move retval from stackval to proper place (r3/r4/...) */
644         if (sig->ret->byref) {
645                 DEBUG (printf ("ret by ref\n"));
646                 ppc_lwz (p, ppc_r3, stackval_arg_pos, ppc_r31);
647         } else {
648                 switch (sig->ret->type) {
649                 case MONO_TYPE_VOID:
650                         break;
651                 case MONO_TYPE_BOOLEAN:
652                 case MONO_TYPE_I1:
653                 case MONO_TYPE_U1:
654                         ppc_lbz (p, ppc_r3, stackval_arg_pos, ppc_r31);
655                         break;
656                 case MONO_TYPE_I2:
657                 case MONO_TYPE_U2:
658                         ppc_lhz (p, ppc_r3, stackval_arg_pos, ppc_r31);
659                         break;
660                 case MONO_TYPE_I4:
661                 case MONO_TYPE_U4:
662                 case MONO_TYPE_I:
663                 case MONO_TYPE_U:
664                 case MONO_TYPE_OBJECT:
665                 case MONO_TYPE_STRING:
666                 case MONO_TYPE_CLASS:
667                         ppc_lwz (p, ppc_r3, stackval_arg_pos, ppc_r31);
668                         break;
669                 case MONO_TYPE_I8:
670                         ppc_lwz (p, ppc_r3, stackval_arg_pos, ppc_r31);
671                         ppc_lwz (p, ppc_r4, stackval_arg_pos + 4, ppc_r31);
672                         break;
673                 case MONO_TYPE_R4:
674                         ppc_lfs (p, ppc_f1, stackval_arg_pos, ppc_r31);
675                         break;
676                 case MONO_TYPE_R8:
677                         ppc_lfd (p, ppc_f1, stackval_arg_pos, ppc_r31);
678                         break;
679                 default:
680                         g_error ("Type 0x%x not handled yet in thunk creation", sig->ret->type);
681                         break;
682                 }
683         }
684
685         /* epilog */
686         ppc_lwz  (p, ppc_r11, 0,  ppc_r1);        /* r11     <--- sp[0]   load backchain from caller's function */
687         ppc_lwz  (p, ppc_r0, 4, ppc_r11);         /* r0      <--- r11[4]  load return address */
688         ppc_mtlr (p, ppc_r0);                     /* LR      <--- r0      set return address */
689         ppc_lwz  (p, ppc_r31, -4, ppc_r11);       /* r31     <--- r11[-4] restore r31 */
690         ppc_mr   (p, ppc_r1, ppc_r11);            /* sp      <--- r11     restore stack */
691         ppc_blr  (p);                             /* return */
692
693         DEBUG (printf ("emited code size: %d\n", p - code_buffer));
694         flush_icache (code_buffer, p - code_buffer);
695
696         DEBUG (printf ("Delegate [end emiting]\n"));
697
698         ji = g_new0 (MonoJitInfo, 1);
699         ji->method = method;
700         ji->code_size = p - code_buffer;
701         ji->code_start = code_buffer;
702
703         mono_jit_info_table_add (mono_root_domain, ji);
704
705         return ji->code_start;
706 }