Added time format with only offset. Fixes #22558.
[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 <string.h>
11 #include "ppc-codegen.h"
12 #include "mono/metadata/class.h"
13 #include "mono/metadata/tabledefs.h"
14 #include "mono/interpreter/interp.h"
15 #include "mono/metadata/appdomain.h"
16
17 #ifdef NEED_MPROTECT
18 #include <sys/mman.h>
19 #include <limits.h>    /* for PAGESIZE */
20 #ifndef PAGESIZE
21 #define PAGESIZE 4096
22 #endif
23 #endif
24
25 #define DEBUG(x)
26
27 /* gpointer
28 fake_func (gpointer (*callme)(gpointer), stackval *retval, void *this_obj, stackval *arguments)
29 {
30         guint32 i = 0xc002becd;
31
32         callme = (gpointer) 0x100fabcd;
33
34         *(gpointer*)retval = (gpointer)(*callme) (arguments [0].data.p, arguments [1].data.p, arguments [2].data.p);
35         *(gdouble*) retval = (gdouble)(*callme) (arguments [0].data.f);
36
37         return (gpointer) (*callme) (((MonoType *)arguments [0]. data.p)->data.klass);
38 } */
39
40 #define MIN_CACHE_LINE 8
41
42 static void inline
43 flush_icache (guint8 *code, guint size)
44 {
45         guint i;
46         guint8 *p;
47
48         p = code;
49         for (i = 0; i < size; i += MIN_CACHE_LINE, p += MIN_CACHE_LINE) {
50                 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
51         }
52         asm ("sync");
53         p = code;
54         for (i = 0; i < size; i += MIN_CACHE_LINE, p += MIN_CACHE_LINE) {
55                 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
56         }
57         asm ("sync");
58         asm ("isync");
59 }
60
61 static void
62 disassemble (guint8 *code, int size)
63 {
64         int i;
65         FILE *ofd;
66         const char *tmp = g_getenv("TMP");
67         char *as_file;
68         char *o_file;
69         char *cmd;
70
71         if (tmp == NULL)
72                 tmp = "/tmp";
73         as_file = g_strdup_printf ("%s/test.s", tmp);    
74
75         if (!(ofd = fopen (as_file, "w")))
76                 g_assert_not_reached ();
77
78         fprintf (ofd, "tmp:\n");
79
80         for (i = 0; i < size; ++i) 
81                 fprintf (ofd, ".byte %d\n", (unsigned int) code [i]);
82
83         fclose (ofd);
84 #ifdef __APPLE__
85 #define DIS_CMD "otool -V -v -t"
86 #else
87 #define DIS_CMD "objdump -d"
88 #endif
89         o_file = g_strdup_printf ("%s/test.o", tmp);    
90         cmd = g_strdup_printf ("as %s -o %s", as_file, o_file);
91         system (cmd); 
92         g_free (cmd);
93         cmd = g_strdup_printf (DIS_CMD " %s", o_file);
94         system (cmd);
95         g_free (cmd);
96         g_free (o_file);
97         g_free (as_file);
98 }
99
100
101 #define NOT_IMPLEMENTED(x) \
102                 g_error ("FIXME: %s is not yet implemented. (trampoline)", x);
103
104 #define PROLOG_INS 8
105 #define CALL_INS   2
106 #define EPILOG_INS 6
107 #define FLOAT_REGS 8
108 #define GENERAL_REGS 8
109 #ifdef __APPLE__
110 #define MINIMAL_STACK_SIZE 10
111 #define ALWAYS_ON_STACK(s) s
112 #define FP_ALSO_IN_REG(s) s
113 #define RET_ADDR_OFFSET 8
114 #define STACK_PARAM_OFFSET 24
115 #else
116 #define MINIMAL_STACK_SIZE 5
117 #define ALWAYS_ON_STACK(s)
118 #define FP_ALSO_IN_REG(s) s
119 #define ALIGN_DOUBLES
120 #define RET_ADDR_OFFSET 4
121 #define STACK_PARAM_OFFSET 8
122 #endif
123
124 static void inline
125 add_general (guint *gr, guint *stack_size, guint *code_size, gboolean simple)
126 {
127         if (simple) {
128                 if (*gr >= GENERAL_REGS) {
129                         *stack_size += 4;
130                         *code_size += 8;    /* load from stack, save on stack */
131                 } else {
132                         ALWAYS_ON_STACK (*stack_size += 4);
133                         *code_size += 4;    /* load from stack */
134                 }
135         } else {
136                 if (*gr >= GENERAL_REGS - 1) {
137                         *stack_size += 8;
138 #ifdef ALIGN_DOUBLES
139                         *stack_size += (*stack_size % 8);
140 #endif
141                         *code_size += 16;   /* 2x load from stack, 2x save to stack */
142                 } else {
143                         ALWAYS_ON_STACK (*stack_size += 8);
144                         *code_size += 8;   /* 2x load from stack */
145                 }
146 #ifdef ALIGN_DOUBLES
147                 if ((*gr) & 1)
148                         (*gr) ++;
149 #endif
150                 (*gr) ++;
151         }
152         (*gr) ++;
153 }
154
155 static void inline
156 calculate_sizes (MonoMethodSignature *sig, guint *stack_size, guint *code_size, gboolean string_ctor, gboolean *use_memcpy)
157 {
158         guint i, fr, gr;
159         guint32 simpletype;
160
161         fr = gr = 0;
162         *stack_size = MINIMAL_STACK_SIZE*4;
163         *code_size  = (PROLOG_INS + CALL_INS + EPILOG_INS)*4;
164
165         if (sig->hasthis) {
166                 add_general (&gr, stack_size, code_size, TRUE);
167         }
168         DEBUG(printf("params: %d\n", sig->param_count));
169         for (i = 0; i < sig->param_count; ++i) {
170                 DEBUG(printf("param %d: ", i));
171                 if (sig->params [i]->byref) {
172                         DEBUG(printf("byref\n"));
173                         add_general (&gr, stack_size, code_size, TRUE);
174                         continue;
175                 }
176                 simpletype = sig->params [i]->type;
177         enum_calc_size:
178                 switch (simpletype) {
179                 case MONO_TYPE_BOOLEAN:
180                 case MONO_TYPE_CHAR:
181                 case MONO_TYPE_I1:
182                 case MONO_TYPE_U1:
183                 case MONO_TYPE_I2:
184                 case MONO_TYPE_U2:
185                 case MONO_TYPE_I4:
186                 case MONO_TYPE_U4:
187                 case MONO_TYPE_I:
188                 case MONO_TYPE_U:
189                 case MONO_TYPE_PTR:
190                 case MONO_TYPE_CLASS:
191                 case MONO_TYPE_OBJECT:
192                 case MONO_TYPE_STRING:
193                         add_general (&gr, stack_size, code_size, TRUE);
194                         break;
195                 case MONO_TYPE_SZARRAY:
196                         add_general (&gr, stack_size, code_size, TRUE);
197                         *code_size += 4;
198                         break;
199                 case MONO_TYPE_VALUETYPE: {
200                         gint size;
201                         if (sig->params [i]->data.klass->enumtype) {
202                                 simpletype = sig->params [i]->data.klass->enum_basetype->type;
203                                 goto enum_calc_size;
204                         }
205                         size = mono_class_value_size (sig->params [i]->data.klass, NULL);
206                         if (size != 4) {
207                                 DEBUG(printf ("copy %d bytes struct on stack\n",
208                                               mono_class_value_size (sig->params [i]->data.klass, NULL)));
209                                 *use_memcpy = TRUE;
210                                 *code_size += 8*4;
211                                 *stack_size += (size + 3) & (~3);
212                                 if (gr > GENERAL_REGS) {
213                                         *code_size += 4;
214                                         *stack_size += 4;
215                                 }
216                         } else {
217                                 DEBUG(printf ("load %d bytes struct\n",
218                                               mono_class_value_size (sig->params [i]->data.klass, NULL)));
219                                 add_general (&gr, stack_size, code_size, TRUE);
220                                 *code_size += 4;
221                         }
222                         break;
223                 }
224                 case MONO_TYPE_I8:
225                         add_general (&gr, stack_size, code_size, FALSE);
226                         break;
227                 case MONO_TYPE_R4:
228                         if (fr < 7) {
229                                 *code_size += 4;
230                                 fr ++;
231                                 FP_ALSO_IN_REG (gr ++);
232                                 ALWAYS_ON_STACK (*stack_size += 4);
233                         } else {
234                                 NOT_IMPLEMENTED ("R4 arg");
235                         }
236                         break;
237                 case MONO_TYPE_R8:
238                         if (fr < 7) {
239                                 *code_size += 4;
240                                 fr ++;
241                                 FP_ALSO_IN_REG (gr += 2);
242                                 ALWAYS_ON_STACK (*stack_size += 8);
243                         } else {
244                                 NOT_IMPLEMENTED ("R8 arg");
245                         }
246                         break;
247                 default:
248                         g_error ("Can't trampoline 0x%x", sig->params [i]->type);
249                 }
250         }
251
252         if (sig->ret->byref || string_ctor) {
253                 *code_size += 8;
254         } else {
255                 simpletype = sig->ret->type;
256 enum_retvalue:
257                 switch (simpletype) {
258                 case MONO_TYPE_BOOLEAN:
259                 case MONO_TYPE_I1:
260                 case MONO_TYPE_U1:
261                 case MONO_TYPE_I2:
262                 case MONO_TYPE_U2:
263                 case MONO_TYPE_CHAR:
264                 case MONO_TYPE_I4:
265                 case MONO_TYPE_U4:
266                 case MONO_TYPE_I:
267                 case MONO_TYPE_U:
268                 case MONO_TYPE_CLASS:
269                 case MONO_TYPE_OBJECT:
270                 case MONO_TYPE_R4:
271                 case MONO_TYPE_R8:
272                 case MONO_TYPE_SZARRAY:
273                 case MONO_TYPE_ARRAY:
274                 case MONO_TYPE_STRING:
275                         *code_size += 8;
276                         break;
277                 case MONO_TYPE_I8:
278                         *code_size += 12;
279                         break;
280                 case MONO_TYPE_VALUETYPE:
281                         if (sig->ret->data.klass->enumtype) {
282                                 simpletype = sig->ret->data.klass->enum_basetype->type;
283                                 goto enum_retvalue;
284                         }
285                         *code_size += 2*4;
286                         break;
287                 case MONO_TYPE_VOID:
288                         break;
289                 default:
290                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
291                 }
292         }
293
294         if (*use_memcpy) {
295                 *stack_size += 2*4;           /* for r14, r15 */
296                 *code_size += 6*4;
297                 if (sig->hasthis) {
298                         *stack_size += 4;     /* for r16 */
299                         *code_size += 4;
300                 }
301         }
302
303         /* align stack size to 16 */
304         DEBUG (printf ("      stack size: %d (%d)\n       code size: %d\n", (*stack_size + 15) & ~15, *stack_size, *code_size));
305         *stack_size = (*stack_size + 15) & ~15;
306 }
307
308 static inline guint8 *
309 emit_prolog (guint8 *p, MonoMethodSignature *sig, guint stack_size)
310 {
311         /* function prolog */
312         ppc_stwu (p, ppc_r1, -stack_size, ppc_r1);     /* sp      <--- sp - stack_size, sp[0] <---- sp save sp, alloc stack */
313         ppc_mflr (p, ppc_r0);                          /* r0      <--- LR */
314         ppc_stw  (p, ppc_r31, stack_size - 4, ppc_r1); /* sp[+4]  <--- r31     save r31 */
315         ppc_stw  (p, ppc_r0, stack_size + RET_ADDR_OFFSET, ppc_r1);  /* sp[-4]  <--- LR      save return address for "callme" */
316         ppc_mr   (p, ppc_r31, ppc_r1);                 /* r31     <--- sp */
317
318         return p;
319 }
320
321 #define ARG_BASE ppc_r12
322 #define ARG_SIZE sizeof (stackval)
323 #define SAVE_4_IN_GENERIC_REGISTER \
324         if (gr < GENERAL_REGS) { \
325                 ppc_lwz  (p, ppc_r3 + gr, i*ARG_SIZE, ARG_BASE); \
326                 gr ++; \
327                 ALWAYS_ON_STACK (stack_par_pos += 4); \
328         } else { \
329                 ppc_lwz  (p, ppc_r11, i*ARG_SIZE, ARG_BASE); \
330                 ppc_stw  (p, ppc_r11, stack_par_pos, ppc_r1); \
331                 stack_par_pos += 4; \
332         }
333 #define SAVE_4_VAL_IN_GENERIC_REGISTER \
334         if (gr < GENERAL_REGS) { \
335                 ppc_lwz  (p, ppc_r3 + gr, i*ARG_SIZE, ARG_BASE); \
336                 ppc_lwz  (p, ppc_r3 + gr, 0, ppc_r3 + gr); \
337                 gr ++; \
338                 ALWAYS_ON_STACK (stack_par_pos += 4); \
339         } else { \
340                 ppc_lwz  (p, ppc_r11, i*ARG_SIZE, ARG_BASE); \
341                 ppc_lwz  (p, ppc_r11, 0, ppc_r11); \
342                 ppc_stw  (p, ppc_r11, stack_par_pos, ppc_r1); \
343                 stack_par_pos += 4; \
344         }
345
346 inline static guint8*
347 emit_save_parameters (guint8 *p, MonoMethodSignature *sig, guint stack_size, gboolean use_memcpy)
348 {
349         guint i, fr, gr, stack_par_pos, struct_pos, cur_struct_pos;
350         guint32 simpletype;
351
352         fr = gr = 0;
353         stack_par_pos = STACK_PARAM_OFFSET;
354
355         ppc_stw  (p, ppc_r4, stack_size - 12, ppc_r31);               /* preserve "retval", sp[+8] */
356
357         if (use_memcpy) {
358                 ppc_stw  (p, ppc_r14, stack_size - 16, ppc_r31);      /* save r14 */
359                 ppc_stw  (p, ppc_r15, stack_size - 20, ppc_r31);      /* save r15 */
360                 ppc_mr   (p, ppc_r14, ppc_r3);                        /* keep "callme" in register */
361                 ppc_mr   (p, ppc_r15, ppc_r6);                        /* keep "arguments" in register */
362         } else {
363                 ppc_mr   (p, ppc_r12, ppc_r6);                        /* keep "arguments" in register */
364                 ppc_mr   (p, ppc_r0, ppc_r3);                         /* keep "callme" in register */
365         }
366
367         if (sig->hasthis) {
368                 if (use_memcpy) {
369                         ppc_stw  (p, ppc_r16, stack_size - 24, ppc_r31);      /* save r16 */
370                         ppc_mr   (p, ppc_r16, ppc_r5);
371                 } else
372                         ppc_mr (p, ppc_r3, ppc_r5);
373                 gr ++;
374                 ALWAYS_ON_STACK (stack_par_pos += 4);
375         }
376
377         if (use_memcpy) {
378                 cur_struct_pos = struct_pos = stack_par_pos;
379                 for (i = 0; i < sig->param_count; ++i) {
380                         if (sig->params [i]->byref)
381                                 continue;
382                         if (sig->params [i]->type == MONO_TYPE_VALUETYPE && !sig->params [i]->data.klass->enumtype) {
383                                 gint size;
384
385                                 size = mono_class_value_size (sig->params [i]->data.klass, NULL);
386                                 if (size != 4) {
387                                         /* call memcpy */
388                                         ppc_addi (p, ppc_r3, ppc_r1, stack_par_pos);
389                                         ppc_lwz  (p, ppc_r4, i*16, ppc_r15);
390                                         /* FIXME check if size > 0xffff */
391                                         ppc_li   (p, ppc_r5, size & 0xffff);
392                                         ppc_lis  (p, ppc_r0, (guint32) memcpy >> 16);
393                                         ppc_ori  (p, ppc_r0, ppc_r0, (guint32) memcpy & 0xffff);
394                                         ppc_mtlr (p, ppc_r0);
395                                         ppc_blrl (p);
396                                         stack_par_pos += (size + 3) & (~3);
397                                 }
398                         }
399                 }
400
401                 if (sig->hasthis) {
402                         ppc_mr   (p, ppc_r3, ppc_r16);
403                         ppc_lwz  (p, ppc_r16, stack_size - 24, ppc_r31);      /* restore r16 */
404                 }
405                 ppc_mr   (p, ppc_r0,  ppc_r14);
406                 ppc_mr   (p, ppc_r12, ppc_r15);
407                 ppc_lwz  (p, ppc_r14, stack_size - 16, ppc_r31);      /* restore r14 */
408                 ppc_lwz  (p, ppc_r15, stack_size - 20, ppc_r31);      /* restore r15 */
409         }
410
411         if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref) {
412                 MonoClass *klass = sig->ret->data.klass;
413                 if (!klass->enumtype) {
414                         gint size = mono_class_native_size (klass, NULL);
415
416                         DEBUG(printf ("retval value type size: %d\n", size));
417                         if (size > 8) {
418                                 ppc_lwz (p, ppc_r3, stack_size - 12, ppc_r31);
419                                 ppc_lwz (p, ppc_r3, 0, ppc_r3);
420                                 gr ++;
421                                 ALWAYS_ON_STACK (stack_par_pos += 4);
422                         } else {
423                                 NOT_IMPLEMENTED ("retval valuetype <= 8 bytes");
424                         }
425                 }
426         }
427
428         for (i = 0; i < sig->param_count; ++i) {
429                 if (sig->params [i]->byref) {
430                         SAVE_4_IN_GENERIC_REGISTER;
431                         continue;
432                 }
433                 simpletype = sig->params [i]->type;
434         enum_calc_size:
435                 switch (simpletype) {
436                 case MONO_TYPE_BOOLEAN:
437                 case MONO_TYPE_I1:
438                 case MONO_TYPE_U1:
439                 case MONO_TYPE_I2:
440                 case MONO_TYPE_U2:
441                 case MONO_TYPE_CHAR:
442                 case MONO_TYPE_I4:
443                 case MONO_TYPE_U4:
444                 case MONO_TYPE_I:
445                 case MONO_TYPE_U:
446                 case MONO_TYPE_PTR:
447                 case MONO_TYPE_CLASS:
448                 case MONO_TYPE_OBJECT:
449                 case MONO_TYPE_STRING:
450                 case MONO_TYPE_SZARRAY:
451                         SAVE_4_IN_GENERIC_REGISTER;
452                         break;
453                 case MONO_TYPE_VALUETYPE: {
454                         gint size;
455                         if (sig->params [i]->data.klass->enumtype) {
456                                 simpletype = sig->params [i]->data.klass->enum_basetype->type;
457                                 goto enum_calc_size;
458                         }
459                         size = mono_class_value_size (sig->params [i]->data.klass, NULL);
460                         if (size == 4) {
461                                 SAVE_4_VAL_IN_GENERIC_REGISTER;
462                         } else {
463                                 if (gr < GENERAL_REGS) {
464                                         ppc_addi (p, ppc_r3 + gr, ppc_r1, cur_struct_pos);
465                                         gr ++;
466                                 } else {
467                                         ppc_lwz  (p, ppc_r11, cur_struct_pos, ppc_r1);
468                                         ppc_stw  (p, ppc_r11, stack_par_pos, ppc_r1);
469                                         stack_par_pos += 4;
470                                 }
471                                 cur_struct_pos += (size + 3) & (~3);
472                         }
473                         break;
474                 }
475                 case MONO_TYPE_I8:
476 DEBUG(printf("Mono_Type_i8. gr = %d, arg_base = %d\n", gr, ARG_BASE));                
477 #ifdef ALIGN_DOUBLES
478                         if (gr & 1)
479                                 gr++;
480 #endif
481                         if (gr < 7) {
482                                 ppc_lwz  (p, ppc_r3 + gr, i*ARG_SIZE, ARG_BASE);
483                                 ppc_lwz  (p, ppc_r3 + gr + 1, i*ARG_SIZE + 4, ARG_BASE);
484                                 ALWAYS_ON_STACK (stack_par_pos += 8);
485                         } else if (gr == 7) {
486                                 ppc_lwz  (p, ppc_r3 + gr, i*ARG_SIZE, ARG_BASE);
487                                 ppc_lwz  (p, ppc_r11, i*ARG_SIZE + 4,  ARG_BASE);
488                                 ppc_stw  (p, ppc_r11, stack_par_pos + 4, ppc_r1);
489                                 stack_par_pos += 8;
490                         } else {
491                                 ppc_lwz  (p, ppc_r11, i*ARG_SIZE, ARG_BASE);
492                                 ppc_stw  (p, ppc_r11, stack_par_pos, ppc_r1);
493                                 ppc_lwz  (p, ppc_r11, i*ARG_SIZE + 4,  ARG_BASE);
494                                 ppc_stw  (p, ppc_r11, stack_par_pos + 4, ppc_r1);
495                                 stack_par_pos += 8;
496                         }
497                         gr += 2;
498                         break;
499                 case MONO_TYPE_R4:
500                         if (fr < 7) {
501                                 ppc_lfs  (p, ppc_f1 + fr, i*ARG_SIZE, ARG_BASE);
502                                 fr ++;
503                                 FP_ALSO_IN_REG (gr ++);
504                                 ALWAYS_ON_STACK (stack_par_pos += 4);
505                         } else {
506                                 NOT_IMPLEMENTED ("r4 on stack");
507                         }
508                         break;
509                 case MONO_TYPE_R8:
510                         if (fr < 7) {
511                                 ppc_lfd  (p, ppc_f1 + fr, i*ARG_SIZE, ARG_BASE);
512                                 fr ++;
513                                 FP_ALSO_IN_REG (gr += 2);
514                                 ALWAYS_ON_STACK (stack_par_pos += 8);
515                         } else {
516                                 NOT_IMPLEMENTED ("r8 on stack");
517                         }
518                         break;
519                 default:
520                         g_error ("Can't trampoline 0x%x", sig->params [i]->type);
521                 }
522         }
523
524         return p;
525 }
526
527 static inline guint8 *
528 alloc_code_memory (guint code_size)
529 {
530         guint8 *p;
531
532 #ifdef NEED_MPROTECT
533         p = g_malloc (code_size + PAGESIZE - 1);
534
535         /* Align to a multiple of PAGESIZE, assumed to be a power of two */
536         p = (char *)(((int) p + PAGESIZE-1) & ~(PAGESIZE-1));
537 #else
538         p = g_malloc (code_size);
539 #endif
540         DEBUG (printf ("           align: %p (%d)\n", p, (guint)p % 4));
541
542         return p;
543 }
544
545 /* static MonoString*
546 mono_string_new_wrapper (const char *text)
547 {
548         return text ? mono_string_new (mono_domain_get (), text) : NULL;
549 } */
550
551 static inline guint8 *
552 emit_call_and_store_retval (guint8 *p, MonoMethodSignature *sig, guint stack_size, gboolean string_ctor)
553 {
554         guint32 simpletype;
555
556         /* call "callme" */
557         ppc_mtlr (p, ppc_r0);
558         ppc_blrl (p);
559
560         /* get return value */
561         if (sig->ret->byref || string_ctor) {
562                 ppc_lwz  (p, ppc_r9, stack_size - 12, ppc_r31);        /* load "retval" address */
563                 ppc_stw  (p, ppc_r3, 0, ppc_r9);                       /* save return value (r3) to "retval" */
564         } else {
565                 simpletype = sig->ret->type;
566 enum_retvalue:
567                 switch (simpletype) {
568                 case MONO_TYPE_BOOLEAN:
569                 case MONO_TYPE_I1:
570                 case MONO_TYPE_U1:
571                         ppc_lwz  (p, ppc_r9, stack_size - 12, ppc_r31);        /* load "retval" address */
572                         ppc_stb  (p, ppc_r3, 0, ppc_r9);                       /* save return value (r3) to "retval" */
573                         break;
574                 case MONO_TYPE_I2:
575                 case MONO_TYPE_U2:
576                 case MONO_TYPE_CHAR:
577                         ppc_lwz  (p, ppc_r9, stack_size - 12, ppc_r31);        /* load "retval" address */
578                         ppc_sth  (p, ppc_r3, 0, ppc_r9);                       /* save return value (r3) to "retval" */
579                         break;
580                 case MONO_TYPE_I4:
581                 case MONO_TYPE_U4:
582                 case MONO_TYPE_I:
583                 case MONO_TYPE_U:
584                 case MONO_TYPE_CLASS:
585                 case MONO_TYPE_OBJECT:
586                 case MONO_TYPE_SZARRAY:
587                 case MONO_TYPE_ARRAY:
588                 case MONO_TYPE_STRING:
589                         ppc_lwz  (p, ppc_r9, stack_size - 12, ppc_r31);        /* load "retval" address */
590                         ppc_stw  (p, ppc_r3, 0, ppc_r9);                       /* save return value (r3) to "retval" */
591                         break;
592                 case MONO_TYPE_R4:
593                         ppc_lwz  (p, ppc_r9, stack_size - 12, ppc_r31);        /* load "retval" address */
594                         ppc_stfs (p, ppc_f1, 0, ppc_r9);                       /* save return value (f1) to "retval" */
595                         break;
596                 case MONO_TYPE_R8:
597                         ppc_lwz  (p, ppc_r9, stack_size - 12, ppc_r31);        /* load "retval" address */
598                         ppc_stfd (p, ppc_f1, 0, ppc_r9);                       /* save return value (f1) to "retval" */
599                         break;
600                 case MONO_TYPE_I8:
601                         ppc_lwz  (p, ppc_r9, stack_size - 12, ppc_r31);        /* load "retval" address */
602                         ppc_stw  (p, ppc_r3, 0, ppc_r9);                       /* save return value (r3) to "retval" */
603                         ppc_stw  (p, ppc_r4, 4, ppc_r9);                       /* save return value (r3) to "retval" */
604                         break;
605                 case MONO_TYPE_VALUETYPE:
606                         if (sig->ret->data.klass->enumtype) {
607                                 simpletype = sig->ret->data.klass->enum_basetype->type;
608                                 goto enum_retvalue;
609                         }
610                         break;
611                 case MONO_TYPE_VOID:
612                         break;
613                 default:
614                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
615                 }
616         }
617
618         return p;
619 }
620
621 static inline guint8 *
622 emit_epilog (guint8 *p, MonoMethodSignature *sig, guint stack_size)
623 {
624         /* function epilog */
625         ppc_lwz  (p, ppc_r11, 0,  ppc_r1);        /* r11     <--- sp[0]   load backchain from caller's function */
626         ppc_lwz  (p, ppc_r0, RET_ADDR_OFFSET, ppc_r11);         /* r0      <--- r11[4]  load return address */
627         ppc_mtlr (p, ppc_r0);                     /* LR      <--- r0      set return address */
628         ppc_lwz  (p, ppc_r31, -4, ppc_r11);       /* r31     <--- r11[-4] restore r31 */
629         ppc_mr   (p, ppc_r1, ppc_r11);            /* sp      <--- r11     restore stack */
630         ppc_blr  (p);                             /* return */
631
632         return p;
633 }
634
635 MonoPIFunc
636 mono_arch_create_trampoline (MonoMethodSignature *sig, gboolean string_ctor)
637 {
638         guint8 *p, *code_buffer;
639         guint stack_size, code_size;
640         gboolean use_memcpy = FALSE;
641
642         DEBUG (printf ("\nPInvoke [start emiting]\n"));
643         calculate_sizes (sig, &stack_size, &code_size, string_ctor, &use_memcpy);
644
645         p = code_buffer = alloc_code_memory (code_size);
646         p = emit_prolog (p, sig, stack_size);
647         p = emit_save_parameters (p, sig, stack_size, use_memcpy);
648         p = emit_call_and_store_retval (p, sig, stack_size, string_ctor);
649         p = emit_epilog (p, sig, stack_size);
650
651         /* {
652                 guchar *cp;
653                 printf (".text\n.align 4\n.globl main\n.type main,@function\nmain:\n");
654                 for (cp = code_buffer; cp < p; cp++) {
655                         printf (".byte 0x%x\n", *cp);
656                 }
657                 } */
658
659 #ifdef NEED_MPROTECT
660         if (mprotect (code_buffer, 1024, PROT_READ | PROT_WRITE | PROT_EXEC)) {
661                 g_error ("Cannot mprotect trampoline\n");
662         }
663 #endif
664
665         DEBUG (printf ("emited code size: %d\n", p - code_buffer));
666         flush_icache (code_buffer, p - code_buffer);
667
668         DEBUG (printf ("PInvoke [end emiting]\n"));
669
670         return (MonoPIFunc) code_buffer;
671         /* return fake_func; */
672 }
673
674
675 #ifdef __APPLE__
676 #define MINV_POS  40  /* MonoInvocation structure offset on stack - STACK_PARAM_OFFSET + 4 pointer args for stackval_from_data */
677 #else
678 #define MINV_POS  8   /* MonoInvocation structure offset on stack */
679 #endif
680 #define STACK_POS (MINV_POS - sizeof (stackval) * sig->param_count)
681 #define OBJ_POS   8
682 #define TYPE_OFFSET (G_STRUCT_OFFSET (stackval, type))
683
684 /*
685  * Returns a pointer to a native function that can be used to
686  * call the specified method.
687  * The function created will receive the arguments according
688  * to the call convention specified in the method.
689  * This function works by creating a MonoInvocation structure,
690  * filling the fields in and calling ves_exec_method on it.
691  * Still need to figure out how to handle the exception stuff
692  * across the managed/unmanaged boundary.
693  */
694 void *
695 mono_arch_create_method_pointer (MonoMethod *method)
696 {
697         MonoMethodSignature *sig;
698         MonoJitInfo *ji;
699         guint8 *p, *code_buffer;
700         guint i, align = 0, code_size, stack_size, stackval_arg_pos, local_pos, local_start, reg_param = 0, stack_param,
701                 cpos, vt_cur;
702         gint *vtbuf;
703         guint32 simpletype;
704
705         code_size = 1024;
706         stack_size = 1024;
707         stack_param = 0;
708
709         sig = mono_method_signature (method);
710
711         p = code_buffer = g_malloc (code_size);
712
713         DEBUG (printf ("\nDelegate [start emiting] %s\n", mono_method_get_name (method)));
714
715         /* prolog */
716         ppc_stwu (p, ppc_r1, -stack_size, ppc_r1);     /* sp      <--- sp - stack_size, sp[0] <---- sp save sp, alloc stack */
717         ppc_mflr (p, ppc_r0);                          /* r0      <--- LR */
718         ppc_stw  (p, ppc_r31, stack_size - 4, ppc_r1); /* sp[+4]  <--- r31     save r31 */
719         ppc_stw  (p, ppc_r0, stack_size + RET_ADDR_OFFSET, ppc_r1);  /* sp[-4]  <--- LR      save return address for "callme" */
720         ppc_mr   (p, ppc_r31, ppc_r1);                 /* r31     <--- sp */
721
722         /* let's fill MonoInvocation */
723         /* first zero some fields */
724         ppc_li   (p, ppc_r0, 0);
725         ppc_stw  (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex)), ppc_r31);
726         ppc_stw  (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex_handler)), ppc_r31);
727         ppc_stw  (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, parent)), ppc_r31);
728
729         /* set method pointer */
730         ppc_lis  (p, ppc_r0,     (guint32) method >> 16);
731         ppc_ori  (p, ppc_r0, ppc_r0, (guint32) method & 0xffff);
732         ppc_stw  (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, method)), ppc_r31);
733
734         local_start = local_pos = MINV_POS + sizeof (MonoInvocation) + (sig->param_count + 1) * sizeof (stackval);
735
736         if (sig->hasthis) {
737                 ppc_stw  (p, ppc_r3, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj)), ppc_r31);
738                 reg_param = 1;
739         } 
740
741         if (sig->param_count) {
742                 gint save_count = MIN (8, sig->param_count + sig->hasthis);
743                 for (i = reg_param; i < save_count; i ++) {
744                         ppc_stw (p, ppc_r3 + i, local_pos, ppc_r31);
745                         local_pos += 4;
746                         DEBUG (printf ("save r%d\n", 4 + i));
747                 }
748         }
749
750         /* prepare space for valuetypes */
751         vt_cur = local_pos;
752         vtbuf = alloca (sizeof(int)*sig->param_count);
753         cpos = 0;
754         for (i = 0; i < sig->param_count; i++) {
755                 MonoType *type = sig->params [i];
756                 vtbuf [i] = -1;
757                 if (type->type == MONO_TYPE_VALUETYPE) {
758                         MonoClass *klass = type->data.klass;
759                         gint size;
760
761                         if (klass->enumtype)
762                                 continue;
763                         size = mono_class_native_size (klass, &align);
764                         cpos += align - 1;
765                         cpos &= ~(align - 1);
766                         vtbuf [i] = cpos;
767                         cpos += size;
768                 }       
769         }
770         cpos += 3;
771         cpos &= ~3;
772
773         local_pos += cpos;
774
775         /* set MonoInvocation::stack_args */
776         stackval_arg_pos = MINV_POS + sizeof (MonoInvocation);
777         ppc_addi (p, ppc_r0, ppc_r31, stackval_arg_pos);
778         ppc_stw  (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, stack_args)), ppc_r31);
779
780         /* add stackval arguments */
781         for (i = 0; i < sig->param_count; ++i) {
782                 if (reg_param < 8) {
783                         ppc_addi (p, ppc_r5, ppc_r31, local_start + i*4);
784                         reg_param ++;
785                 } else {
786                         ppc_addi (p, ppc_r5, stack_size + 8 + stack_param, ppc_r31);
787                         stack_param ++;
788                 }
789                 ppc_lis  (p, ppc_r3, (guint32) sig->params [i] >> 16);
790
791                 if (vtbuf [i] >= 0) {
792                         ppc_addi (p, ppc_r4, ppc_r31, vt_cur);
793                         ppc_stw  (p, ppc_r4, stackval_arg_pos, ppc_r31);
794                         ppc_addi (p, ppc_r4, ppc_r31, stackval_arg_pos);
795                         ppc_lwz  (p, ppc_r5, 0, ppc_r5);
796                         vt_cur += vtbuf [i];
797                 } else {
798                         ppc_addi (p, ppc_r4, ppc_r31, stackval_arg_pos);
799                 }
800                 ppc_ori  (p, ppc_r3, ppc_r3, (guint32) sig->params [i] & 0xffff);
801                 ppc_lis  (p, ppc_r0, (guint32) stackval_from_data >> 16);
802                 ppc_li   (p, ppc_r6, sig->pinvoke);
803                 ppc_ori  (p, ppc_r0, ppc_r0, (guint32) stackval_from_data & 0xffff);
804                 ppc_mtlr (p, ppc_r0);
805                 ppc_blrl (p);
806
807                 stackval_arg_pos += sizeof (stackval);
808         }
809
810         /* return value storage */
811         if (sig->param_count) {
812                 ppc_addi (p, ppc_r0, ppc_r31, stackval_arg_pos);
813         }
814         ppc_stw  (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, retval)), ppc_r31);
815
816         /* call ves_exec_method */
817         ppc_lis  (p, ppc_r0,     (guint32) ves_exec_method >> 16);
818         ppc_addi (p, ppc_r3, ppc_r31, MINV_POS);
819         ppc_ori  (p, ppc_r0, ppc_r0, (guint32) ves_exec_method & 0xffff);
820         ppc_mtlr (p, ppc_r0);
821         ppc_blrl (p);
822
823         /* move retval from stackval to proper place (r3/r4/...) */
824         if (sig->ret->byref) {
825                 DEBUG (printf ("ret by ref\n"));
826                 ppc_lwz (p, ppc_r3, stackval_arg_pos, ppc_r31);
827         } else {
828         enum_retvalue:
829                 switch (sig->ret->type) {
830                 case MONO_TYPE_VOID:
831                         break;
832                 case MONO_TYPE_BOOLEAN:
833                 case MONO_TYPE_I1:
834                 case MONO_TYPE_U1:
835                         ppc_lbz (p, ppc_r3, stackval_arg_pos, ppc_r31);
836                         break;
837                 case MONO_TYPE_I2:
838                 case MONO_TYPE_U2:
839                         ppc_lhz (p, ppc_r3, stackval_arg_pos, ppc_r31);
840                         break;
841                 case MONO_TYPE_I4:
842                 case MONO_TYPE_U4:
843                 case MONO_TYPE_I:
844                 case MONO_TYPE_U:
845                 case MONO_TYPE_OBJECT:
846                 case MONO_TYPE_STRING:
847                 case MONO_TYPE_CLASS:
848                         ppc_lwz (p, ppc_r3, stackval_arg_pos, ppc_r31);
849                         break;
850                 case MONO_TYPE_I8:
851                         ppc_lwz (p, ppc_r3, stackval_arg_pos, ppc_r31);
852                         ppc_lwz (p, ppc_r4, stackval_arg_pos + 4, ppc_r31);
853                         break;
854                 case MONO_TYPE_R4:
855                         ppc_lfs (p, ppc_f1, stackval_arg_pos, ppc_r31);
856                         break;
857                 case MONO_TYPE_R8:
858                         ppc_lfd (p, ppc_f1, stackval_arg_pos, ppc_r31);
859                         break;
860                 case MONO_TYPE_VALUETYPE:
861                         if (sig->ret->data.klass->enumtype) {
862                                 simpletype = sig->ret->data.klass->enum_basetype->type;
863                                 goto enum_retvalue;
864                         }
865                         NOT_IMPLEMENTED ("value type as ret val from delegate");
866                         break;
867                 default:
868                         g_error ("Type 0x%x not handled yet in thunk creation", sig->ret->type);
869                         break;
870                 }
871         }
872
873         /* epilog */
874         ppc_lwz  (p, ppc_r11, 0,  ppc_r1);        /* r11     <--- sp[0]   load backchain from caller's function */
875         ppc_lwz  (p, ppc_r0, RET_ADDR_OFFSET, ppc_r11);         /* r0      <--- r11[4]  load return address */
876         ppc_mtlr (p, ppc_r0);                     /* LR      <--- r0      set return address */
877         ppc_lwz  (p, ppc_r31, -4, ppc_r11);       /* r31     <--- r11[-4] restore r31 */
878         ppc_mr   (p, ppc_r1, ppc_r11);            /* sp      <--- r11     restore stack */
879         ppc_blr  (p);                             /* return */
880
881         DEBUG (printf ("emited code size: %d\n", p - code_buffer));
882         DEBUG (disassemble (code_buffer, p - code_buffer));
883         flush_icache (code_buffer, p - code_buffer);
884
885         DEBUG (printf ("Delegate [end emiting]\n"));
886
887         ji = g_new0 (MonoJitInfo, 1);
888         ji->method = method;
889         ji->code_size = p - code_buffer;
890         ji->code_start = code_buffer;
891
892         mono_jit_info_table_add (mono_get_root_domain (), ji);
893
894         return ji->code_start;
895 }