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