ppc changes
[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
15 #ifdef NEED_MPROTECT
16 #include <sys/mman.h>
17 #include <limits.h>    /* for PAGESIZE */
18 #ifndef PAGESIZE
19 #define PAGESIZE 4096
20 #endif
21 #endif
22
23 /* void
24 fake_func (gdouble (*callme)(), stackval *retval, void *this_obj, stackval *arguments)
25 {
26         guint32 i = 0xc002becd;
27
28         callme = (gpointer) 0x100fabcd;
29
30         *(gpointer*)retval = (gpointer)(*callme) (arguments [0].data.p, arguments [1].data.p, arguments [2].data.p);
31         *(gdouble*) retval = (gdouble)(*callme) (arguments [0].data.f);
32 } */
33
34 #define MIN_CACHE_LINE 8
35
36 static void inline
37 flush_icache (guint8 *code, guint size)
38 {
39         guint i;
40         guint8 *p;
41
42         p = code;
43         for (i = 0; i < size; i += MIN_CACHE_LINE, p += MIN_CACHE_LINE) {
44                 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
45         }
46         asm ("sync");
47         p = code;
48         for (i = 0; i < size; i += MIN_CACHE_LINE, p += MIN_CACHE_LINE) {
49                 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
50         }
51         asm ("sync");
52         asm ("isync");
53 }
54
55 #define NOT_IMPLEMENTED(x) \
56                 g_error ("FIXME: %s is not yet implemented. (trampoline)", x);
57
58 #define PROLOG_INS 8
59 #define CALL_INS   2
60 #define EPILOG_INS 6
61 #define MINIMAL_STACK_SIZE 4
62 #define FLOAT_REGS 8
63 #define GENERAL_REGS 8
64
65 static void inline
66 add_general (guint *gr, guint *stack_size, guint *code_size, gboolean simple)
67 {
68         if (simple) {
69                 if (*gr >= GENERAL_REGS) {
70                         *stack_size += 4;
71                         *code_size += 8;    /* load from stack, save on stack */
72                 } else {
73                         *code_size += 4;    /* load from stack */
74                 }
75         } else {
76                 if (*gr >= GENERAL_REGS - 1) {
77                         *stack_size += 8 + (*stack_size % 8);
78                         *code_size += 16;   /* 2x load from stack, save to stack */
79                 } else {
80                         *code_size += 16;   /* 2x load from stack */
81                 }
82                 (*gr) ++;
83         }
84         (*gr) ++;
85 }
86
87 static void inline
88 calculate_sizes (MonoMethod *method, guint *stack_size, guint *code_size, guint *strings, gint runtime)
89 {
90         MonoMethodSignature *sig;
91         guint i, fr, gr;
92         guint32 simpletype;
93
94         fr = gr = 0;
95         *stack_size = MINIMAL_STACK_SIZE*4;
96         *code_size  = (PROLOG_INS + CALL_INS + EPILOG_INS)*4;
97         *strings = 0;
98
99         sig = method->signature;
100         if (sig->hasthis) {
101                 add_general (&gr, stack_size, code_size, TRUE);
102         }
103
104         for (i = 0; i < sig->param_count; ++i) {
105                 if (sig->params [i]->byref) {
106                         add_general (&gr, stack_size, code_size, TRUE);
107                         continue;
108                 }
109                 simpletype = sig->params [i]->type;
110         enum_calc_size:
111                 switch (simpletype) {
112                 case MONO_TYPE_BOOLEAN:
113                 case MONO_TYPE_CHAR:
114                 case MONO_TYPE_I1:
115                 case MONO_TYPE_U1:
116                 case MONO_TYPE_I2:
117                 case MONO_TYPE_U2:
118                 case MONO_TYPE_I4:
119                 case MONO_TYPE_U4:
120                 case MONO_TYPE_I:
121                 case MONO_TYPE_U:
122                 case MONO_TYPE_PTR:
123                 case MONO_TYPE_SZARRAY:
124                 case MONO_TYPE_CLASS:
125                 case MONO_TYPE_OBJECT:
126                         add_general (&gr, stack_size, code_size, TRUE);
127                         break;
128                 case MONO_TYPE_VALUETYPE:
129                         if (sig->params [i]->data.klass->enumtype) {
130                                 simpletype = sig->params [i]->data.klass->enum_basetype->type;
131                                 goto enum_calc_size;
132                         }
133                         if (mono_class_value_size (sig->params [i]->data.klass, NULL) != 4)
134                                 g_error ("can only marshal enums, not generic structures (size: %d)",
135                                          mono_class_value_size (sig->params [i]->data.klass, NULL));
136                         add_general (&gr, stack_size, code_size, TRUE);
137                         *code_size += 4;
138                         break;
139                 case MONO_TYPE_STRING:
140                         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || runtime) {
141                                 add_general (&gr, stack_size, code_size, TRUE);
142                                 break;
143                         }
144                         (*strings) ++;
145                         *code_size += 12*4;
146                         *stack_size += 4;
147                         break;
148                 case MONO_TYPE_I8:
149                         add_general (&gr, stack_size, code_size, FALSE);
150                         break;
151                 case MONO_TYPE_R4:
152                 case MONO_TYPE_R8:
153                         if (fr < 7) {
154                                 *code_size += 4;
155                                 fr ++;
156                         } else {
157                                 NOT_IMPLEMENTED ("R8 arg");
158                         }
159                         break;
160                 default:
161                         g_error ("Can't trampoline 0x%x", sig->params [i]->type);
162                 }
163         }
164
165         if (sig->ret->byref) {
166                 *code_size += 8;
167         } else {
168                 simpletype = sig->ret->type;
169 enum_retvalue:
170                 switch (simpletype) {
171                 case MONO_TYPE_BOOLEAN:
172                 case MONO_TYPE_I1:
173                 case MONO_TYPE_U1:
174                 case MONO_TYPE_I4:
175                 case MONO_TYPE_U4:
176                 case MONO_TYPE_I:
177                 case MONO_TYPE_U:
178                 case MONO_TYPE_CLASS:
179                 case MONO_TYPE_OBJECT:
180                 case MONO_TYPE_R4:
181                 case MONO_TYPE_R8:
182                 case MONO_TYPE_SZARRAY:
183                 case MONO_TYPE_ARRAY:
184                 case MONO_TYPE_STRING:
185                         *code_size += 8;
186                         break;
187                 case MONO_TYPE_I8:
188                         *code_size += 12;
189                         break;
190                 case MONO_TYPE_VALUETYPE:
191                         if (sig->ret->data.klass->enumtype) {
192                                 simpletype = sig->ret->data.klass->enum_basetype->type;
193                                 goto enum_retvalue;
194                         }
195                         NOT_IMPLEMENTED ("valuetype");
196                         break;
197                 case MONO_TYPE_VOID:
198                         break;
199                 default:
200                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
201                 }
202         }
203
204         if (*strings) {
205                 /* space to keep parameters and prepared strings */
206                  *stack_size += 8;
207                  *code_size += 16;
208                  if (sig->hasthis) {
209                          *stack_size += 4;
210                          *code_size  += 12;
211                  }
212         }
213         /* align stack size to 16 */
214         printf ("      stack size: %d (%d)\n       code size: %d\n", (*stack_size + 15) & ~15, *stack_size, *code_size);
215         *stack_size = (*stack_size + 15) & ~15;
216
217 }
218
219 static inline guint8 *
220 emit_prolog (guint8 *p, MonoMethod *method, guint stack_size, guint strings)
221 {
222         /* function prolog */
223         ppc_stwu (p, ppc_r1, -stack_size, ppc_r1);     /* sp      <--- sp - stack_size, sp[0] <---- sp save sp, alloc stack */
224         ppc_mflr (p, ppc_r0);                          /* r0      <--- LR */
225         ppc_stw  (p, ppc_r31, stack_size - 4, ppc_r1); /* sp[+4]  <--- r31     save r31 */
226         ppc_stw  (p, ppc_r0, stack_size + 4, ppc_r1);  /* sp[-4]  <--- LR      save return address for "callme" */
227         ppc_mr   (p, ppc_r31, ppc_r1);                 /* r31     <--- sp */
228
229         /* handle our parameters */
230         if (strings) {
231                 ppc_stw  (p, ppc_r30, 16, ppc_r1);
232                 ppc_stw  (p, ppc_r29, 20, ppc_r1);
233                 if (method->signature->hasthis) {
234                         ppc_stw  (p, ppc_r28, 24, ppc_r1);
235                 }
236                 ppc_mr   (p, ppc_r30, ppc_r6);                        /* args */
237                 ppc_mr   (p, ppc_r29, ppc_r3);                        /* callme */
238                 if (method->signature->hasthis) {
239                         ppc_mr   (p, ppc_r28, ppc_r5);                /* this */
240                 }
241         } else {
242                 ppc_mr   (p, ppc_r12, ppc_r6);                        /* keep "arguments" in register */
243                 ppc_mr   (p, ppc_r0, ppc_r3);                         /* keep "callme" in register */
244         }
245         ppc_stw  (p, ppc_r4, 8, ppc_r31);                             /* preserve "retval", sp[+8] */
246
247         return p;
248 }
249
250 #define ARG_BASE strings ? ppc_r30 : ppc_r12
251 #define SAVE_4_IN_GENERIC_REGISTER \
252                         if (gr < GENERAL_REGS) { \
253                                 ppc_lwz  (p, ppc_r3 + gr, i*16, ARG_BASE); \
254                                 gr ++; \
255                         } else { \
256                                 NOT_IMPLEMENTED("save on stack"); \
257                         }
258
259 inline static guint8*
260 emit_save_parameters (guint8 *p, MonoMethod *method, guint strings, gint runtime)
261 {
262         MonoMethodSignature *sig;
263         guint i, fr, gr, act_strs;
264         guint32 simpletype;
265
266         fr = gr = 0;
267         act_strs = 0;
268         sig = method->signature;
269
270         if (strings) {
271                 for (i = 0; i < sig->param_count; ++i) {
272                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_STRING) {
273                                 ppc_lis  (p, ppc_r0,     (guint32) mono_string_to_utf8 >> 16);
274                                 ppc_lwz  (p, ppc_r3, i*16, ppc_r30);
275                                 ppc_ori  (p, ppc_r0, ppc_r0, (guint32) mono_string_to_utf8 & 0xffff);
276                                 ppc_mtlr (p, ppc_r0);
277                                 ppc_blrl (p);
278                                 ppc_stw  (p, ppc_r3, 24 + act_strs, ppc_r31);
279                                 act_strs += 4;
280                         }
281                 }
282         }
283
284         if (sig->hasthis) {
285                 ppc_mr (p, ppc_r3, ppc_r5);
286                 gr ++;
287         }
288
289         act_strs = 0;
290         for (i = 0; i < sig->param_count; ++i) {
291                 if (sig->params [i]->byref) {
292                         SAVE_4_IN_GENERIC_REGISTER;
293                         continue;
294                 }
295                 simpletype = sig->params [i]->type;
296         enum_calc_size:
297                 switch (simpletype) {
298                 case MONO_TYPE_BOOLEAN:
299                 case MONO_TYPE_CHAR:
300                 case MONO_TYPE_I1:
301                 case MONO_TYPE_U1:
302                 case MONO_TYPE_I2:
303                 case MONO_TYPE_U2:
304                 case MONO_TYPE_I4:
305                 case MONO_TYPE_U4:
306                 case MONO_TYPE_I:
307                 case MONO_TYPE_U:
308                 case MONO_TYPE_PTR:
309                 case MONO_TYPE_SZARRAY:
310                 case MONO_TYPE_CLASS:
311                 case MONO_TYPE_OBJECT:
312                         SAVE_4_IN_GENERIC_REGISTER;
313                         break;
314                 case MONO_TYPE_VALUETYPE:
315                         if (sig->params [i]->data.klass->enumtype) {
316                                 simpletype = sig->params [i]->data.klass->enum_basetype->type;
317                                 goto enum_calc_size;
318                         }
319                         if (mono_class_value_size (sig->params [i]->data.klass, NULL) != 4)
320                                 g_error ("can only marshal enums, not generic structures (size: %d)",
321                                          mono_class_value_size (sig->params [i]->data.klass, NULL));
322                         if (gr < GENERAL_REGS) {
323                                 ppc_lwz  (p, ppc_r3 + gr, i*16, ARG_BASE);
324                                 ppc_lwz  (p, ppc_r3 + gr, 0, ppc_r3 + gr);
325                                 gr ++;
326                         } else {
327                                 NOT_IMPLEMENTED ("save value type on stack");
328                         }
329                         break;
330                 case MONO_TYPE_STRING:
331                         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || runtime) {
332                                 SAVE_4_IN_GENERIC_REGISTER;
333                         } else {
334                                 if (gr < 8) {
335                                         ppc_lwz (p, ppc_r3 + gr, 24 + act_strs * 4, ppc_r31);
336                                         gr ++;
337                                         act_strs ++;
338                                 } else
339                                         NOT_IMPLEMENTED ("string on stack");
340                         }
341                         break;
342                 case MONO_TYPE_I8:
343                         if (gr < 7) {
344                                 g_warning ("check endianess");
345                                 ppc_lwz  (p, ppc_r3 + gr, i*16, ARG_BASE);
346                                 gr ++;
347                                 ppc_lwz  (p, ppc_r3 + gr, i*17, ARG_BASE);
348                                 gr ++;
349                         } else {
350                                 NOT_IMPLEMENTED ("i8 on stack");
351                         }
352                         break;
353                 case MONO_TYPE_R4:
354                         if (fr < 7) {
355                                 ppc_lfs  (p, ppc_f1 + fr, i*16, ARG_BASE);
356                                 fr ++;
357                         } else {
358                                 NOT_IMPLEMENTED ("r4 on stack");
359                         }
360                         break;
361                 case MONO_TYPE_R8:
362                         if (fr < 7) {
363                                 ppc_lfd  (p, ppc_f1 + fr, i*16, ARG_BASE);
364                                 fr ++;
365                         } else {
366                                 NOT_IMPLEMENTED ("r8 on stack");
367                         }
368                         break;
369                 default:
370                         g_error ("Can't trampoline 0x%x", sig->params [i]->type);
371                 }
372         }
373
374         return p;
375 }
376
377 static inline guint8 *
378 alloc_code_memory (guint code_size)
379 {
380         guint8 *p;
381
382 #ifdef NEED_MPROTECT
383         p = g_malloc (code_size + PAGESIZE - 1);
384
385         /* Align to a multiple of PAGESIZE, assumed to be a power of two */
386         p = (char *)(((int) p + PAGESIZE-1) & ~(PAGESIZE-1));
387 #else
388         p = g_malloc (code_size);
389 #endif
390         printf ("           align: %p (%d)\n", p, (guint)p % 4);
391
392         return p;
393 }
394
395 static inline guint8 *
396 emit_call_and_store_retval (guint8 *p, MonoMethod *method, guint strings)
397 {
398         MonoMethodSignature *sig = method->signature;
399         guint32 simpletype;
400
401         /* call "callme" */
402         ppc_mtlr (p, strings ? ppc_r29 : ppc_r0);
403         ppc_blrl (p);
404
405         /* get return value */
406         if (sig->ret->byref) {
407                 ppc_lwz  (p, ppc_r9, 8, ppc_r31);        /* load "retval" address */
408                 ppc_stw  (p, ppc_r3, 0, ppc_r9);         /* save return value (r3) to "retval" */
409         } else {
410                 simpletype = sig->ret->type;
411 enum_retvalue:
412                 switch (simpletype) {
413                 case MONO_TYPE_BOOLEAN:
414                 case MONO_TYPE_I1:
415                 case MONO_TYPE_U1:
416                         ppc_lwz  (p, ppc_r9, 8, ppc_r31);        /* load "retval" address */
417                         ppc_stb  (p, ppc_r3, 0, ppc_r9);         /* save return value (r3) to "retval" */
418                         break;
419                 case MONO_TYPE_I4:
420                 case MONO_TYPE_U4:
421                 case MONO_TYPE_I:
422                 case MONO_TYPE_U:
423                 case MONO_TYPE_CLASS:
424                 case MONO_TYPE_OBJECT:
425                 case MONO_TYPE_SZARRAY:
426                 case MONO_TYPE_ARRAY:
427                 case MONO_TYPE_STRING:
428                         ppc_lwz  (p, ppc_r9, 8, ppc_r31);        /* load "retval" address */
429                         ppc_stw  (p, ppc_r3, 0, ppc_r9);         /* save return value (r3) to "retval" */
430                         break;
431                 case MONO_TYPE_R4:
432                         ppc_lwz  (p, ppc_r9, 8, ppc_r31);        /* load "retval" address */
433                         ppc_stfs (p, ppc_f1, 0, ppc_r9);         /* save return value (f1) to "retval" */
434                         break;
435                 case MONO_TYPE_R8:
436                         ppc_lwz  (p, ppc_r9, 8, ppc_r31);        /* load "retval" address */
437                         ppc_stfd (p, ppc_f1, 0, ppc_r9);         /* save return value (f1) to "retval" */
438                         break;
439                 case MONO_TYPE_I8:
440                         g_warning ("check endianess");
441                         ppc_lwz  (p, ppc_r9, 8, ppc_r31);        /* load "retval" address */
442                         ppc_stw  (p, ppc_r3, 0, ppc_r9);         /* save return value (r3) to "retval" */
443                         ppc_stw  (p, ppc_r4, 4, ppc_r9);         /* save return value (r3) to "retval" */
444                         break;
445                 case MONO_TYPE_VALUETYPE:
446                         if (sig->ret->data.klass->enumtype) {
447                                 simpletype = sig->ret->data.klass->enum_basetype->type;
448                                 goto enum_retvalue;
449                         }
450                         NOT_IMPLEMENTED ("retval valuetype");
451                         break;
452                 case MONO_TYPE_VOID:
453                         break;
454                 default:
455                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
456                 }
457         }
458
459         return p;
460 }
461
462 static inline guint8 *
463 emit_epilog (guint8 *p, MonoMethod *method, guint strings)
464 {
465         if (strings) {
466                 MonoMethodSignature *sig = method->signature;
467                 guint i, act_strs;
468
469                 /* free allocated memory */
470                 act_strs = 0;
471                 for (i = 0; i < sig->param_count; ++i) {
472                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_STRING) {
473                                 ppc_lis  (p, ppc_r0,     (guint32) g_free >> 16);
474                                 ppc_lwz  (p, ppc_r3, 24 + act_strs, ppc_r31);
475                                 ppc_ori  (p, ppc_r0, ppc_r0, (guint32) g_free & 0xffff);
476                                 ppc_mtlr (p, ppc_r0);
477                                 ppc_blrl (p);
478                                 act_strs += 4;
479                         }
480                 }
481
482                 /* restore volatile registers */
483                 ppc_lwz  (p, ppc_r30, 16, ppc_r1);
484                 ppc_lwz  (p, ppc_r29, 20, ppc_r1);
485                 if (method->signature->hasthis) {
486                         ppc_lwz  (p, ppc_r28, 24, ppc_r1);
487                 }
488         }
489
490         /* function epilog */
491         ppc_lwz  (p, ppc_r11, 0,  ppc_r1);        /* r11     <--- sp[0]   load backchain from caller's function */
492         ppc_lwz  (p, ppc_r0, 4, ppc_r11);         /* r0      <--- r11[4]  load return address */
493         ppc_mtlr (p, ppc_r0);                     /* LR      <--- r0      set return address */
494         ppc_lwz  (p, ppc_r31, -4, ppc_r11);       /* r31     <--- r11[-4] restore r31 */
495         ppc_mr   (p, ppc_r1, ppc_r11);            /* sp      <--- r11     restore stack */
496         ppc_blr  (p);                             /* return */
497
498         return p;
499 }
500
501 MonoPIFunc
502 mono_create_trampoline (MonoMethod *method, int runtime)
503 {
504         guint8 *p, *code_buffer;
505         guint stack_size, code_size, strings;
506
507         printf ("\nPInvoke [start emiting] %s\n", method->name);
508         calculate_sizes (method, &stack_size, &code_size, &strings, runtime);
509
510         p = code_buffer = alloc_code_memory (code_size);
511         p = emit_prolog (p, method, stack_size, strings);
512         p = emit_save_parameters (p, method, strings, runtime);
513         p = emit_call_and_store_retval (p, method, strings);
514         p = emit_epilog (p, method, strings);
515
516         /* {
517                 guchar *cp;
518                 printf (".text\n.align 4\n.globl main\n.type main,@function\nmain:\n");
519                 for (cp = code_buffer; cp < p; cp++) {
520                         printf (".byte 0x%x\n", *cp);
521                 }
522                 } */
523
524 #ifdef NEED_MPROTECT
525         if (mprotect (code_buffer, 1024, PROT_READ | PROT_WRITE | PROT_EXEC)) {
526                 g_error ("Cannot mprotect trampoline\n");
527         }
528 #endif
529
530         printf ("emited code size: %d\n", p - code_buffer);
531         flush_icache (code_buffer, p - code_buffer);
532
533         printf ("PInvoke [end emiting]\n");
534
535         return (MonoPIFunc) code_buffer;
536         /* return fake_func; */
537 }
538
539
540 #define MINV_POS  (- sizeof (MonoInvocation))
541 #define STACK_POS (MINV_POS - sizeof (stackval) * sig->param_count)
542 #define OBJ_POS   8
543 #define TYPE_OFFSET (G_STRUCT_OFFSET (stackval, type))
544
545 /*
546  * Returns a pointer to a native function that can be used to
547  * call the specified method.
548  * The function created will receive the arguments according
549  * to the call convention specified in the method.
550  * This function works by creating a MonoInvocation structure,
551  * filling the fields in and calling ves_exec_method on it.
552  * Still need to figure out how to handle the exception stuff
553  * across the managed/unmanaged boundary.
554  */
555 void *
556 mono_create_method_pointer (MonoMethod *method)
557 {
558         return NULL;
559 }
560
561