f0db45d04cd75df5042689cd15eaae5b00a0f72a
[mono.git] / mono / arch / ppc / tramp.c
1 /*
2  * Create trampolines to invoke arbitrary functions.
3  * 
4  * Copyright (C) Radek Doulik
5  * 
6  */
7
8 #include "config.h"
9 #include <stdlib.h>
10 #include "ppc-codegen.h"
11 #include "mono/metadata/class.h"
12 #include "mono/metadata/tabledefs.h"
13 #include "mono/interpreter/interp.h"
14 #include "mono/metadata/appdomain.h"
15
16 #ifdef NEED_MPROTECT
17 #include <sys/mman.h>
18 #include <limits.h>    /* for PAGESIZE */
19 #ifndef PAGESIZE
20 #define PAGESIZE 4096
21 #endif
22 #endif
23
24 #define DEBUG(x)
25
26 /* gpointer
27 fake_func (gpointer (*callme)(gpointer), stackval *retval, void *this_obj, stackval *arguments)
28 {
29         guint32 i = 0xc002becd;
30
31         callme = (gpointer) 0x100fabcd;
32
33         *(gpointer*)retval = (gpointer)(*callme) (arguments [0].data.p, arguments [1].data.p, arguments [2].data.p);
34         *(gdouble*) retval = (gdouble)(*callme) (arguments [0].data.f);
35
36         return (gpointer) (*callme) (((MonoType *)arguments [0]. data.p)->data.klass);
37 } */
38
39 #define MIN_CACHE_LINE 8
40
41 static void inline
42 flush_icache (guint8 *code, guint size)
43 {
44         guint i;
45         guint8 *p;
46
47         p = code;
48         for (i = 0; i < size; i += MIN_CACHE_LINE, p += MIN_CACHE_LINE) {
49                 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
50         }
51         asm ("sync");
52         p = code;
53         for (i = 0; i < size; i += MIN_CACHE_LINE, p += MIN_CACHE_LINE) {
54                 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
55         }
56         asm ("sync");
57         asm ("isync");
58 }
59
60 #define NOT_IMPLEMENTED(x) \
61                 g_error ("FIXME: %s is not yet implemented. (trampoline)", x);
62
63 #define PROLOG_INS 8
64 #define CALL_INS   2
65 #define EPILOG_INS 6
66 #define MINIMAL_STACK_SIZE 5
67 #define FLOAT_REGS 8
68 #define GENERAL_REGS 8
69
70 static void inline
71 add_general (guint *gr, guint *stack_size, guint *code_size, gboolean simple)
72 {
73         if (simple) {
74                 if (*gr >= GENERAL_REGS) {
75                         *stack_size += 4;
76                         *code_size += 8;    /* load from stack, save on stack */
77                 } else {
78                         *code_size += 4;    /* load from stack */
79                 }
80         } else {
81                 if (*gr >= GENERAL_REGS - 1) {
82                         *stack_size += 8 + (*stack_size % 8);
83                         *code_size += 16;   /* 2x load from stack, 2x save to stack */
84                 } else {
85                         *code_size += 16;   /* 2x load from stack */
86                 }
87                 if ((*gr) && 1)
88                         (*gr) ++;
89                 (*gr) ++;
90         }
91         (*gr) ++;
92 }
93
94 static void inline
95 calculate_sizes (MonoMethod *method, guint *stack_size, guint *code_size, guint *strings, gint runtime)
96 {
97         MonoMethodSignature *sig;
98         guint i, fr, gr;
99         guint32 simpletype;
100
101         fr = gr = 0;
102         *stack_size = MINIMAL_STACK_SIZE*4;
103         *code_size  = (PROLOG_INS + CALL_INS + EPILOG_INS)*4;
104         *strings = 0;
105
106         sig = method->signature;
107         if (sig->hasthis) {
108                 add_general (&gr, stack_size, code_size, TRUE);
109         }
110
111         for (i = 0; i < sig->param_count; ++i) {
112                 if (sig->params [i]->byref) {
113                         add_general (&gr, stack_size, code_size, TRUE);
114                         continue;
115                 }
116                 simpletype = sig->params [i]->type;
117         enum_calc_size:
118                 switch (simpletype) {
119                 case MONO_TYPE_BOOLEAN:
120                 case MONO_TYPE_CHAR:
121                 case MONO_TYPE_I1:
122                 case MONO_TYPE_U1:
123                 case MONO_TYPE_I2:
124                 case MONO_TYPE_U2:
125                 case MONO_TYPE_I4:
126                 case MONO_TYPE_U4:
127                 case MONO_TYPE_I:
128                 case MONO_TYPE_U:
129                 case MONO_TYPE_PTR:
130                 case MONO_TYPE_SZARRAY:
131                 case MONO_TYPE_CLASS:
132                 case MONO_TYPE_OBJECT:
133                         add_general (&gr, stack_size, code_size, TRUE);
134                         break;
135                 case MONO_TYPE_VALUETYPE:
136                         if (sig->params [i]->data.klass->enumtype) {
137                                 simpletype = sig->params [i]->data.klass->enum_basetype->type;
138                                 goto enum_calc_size;
139                         }
140                         if (mono_class_value_size (sig->params [i]->data.klass, NULL) != 4)
141                                 g_error ("can only marshal enums, not generic structures (size: %d)",
142                                          mono_class_value_size (sig->params [i]->data.klass, NULL));
143                         add_general (&gr, stack_size, code_size, TRUE);
144                         *code_size += 4;
145                         break;
146                 case MONO_TYPE_STRING:
147                         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || runtime) {
148                                 add_general (&gr, stack_size, code_size, TRUE);
149                                 break;
150                         }
151                         (*strings) ++;
152                         *code_size += 12*4;
153                         *stack_size += 4;
154                         break;
155                 case MONO_TYPE_I8:
156                         add_general (&gr, stack_size, code_size, FALSE);
157                         break;
158                 case MONO_TYPE_R4:
159                 case MONO_TYPE_R8:
160                         if (fr < 7) {
161                                 *code_size += 4;
162                                 fr ++;
163                         } else {
164                                 NOT_IMPLEMENTED ("R8 arg");
165                         }
166                         break;
167                 default:
168                         g_error ("Can't trampoline 0x%x", sig->params [i]->type);
169                 }
170         }
171
172         if (sig->ret->byref ||
173             (method->klass == mono_defaults.string_class &&
174              *method->name == '.' && !strcmp (method->name, ".ctor"))) {
175                 *code_size += 8;
176         } else {
177                 simpletype = sig->ret->type;
178 enum_retvalue:
179                 switch (simpletype) {
180                 case MONO_TYPE_BOOLEAN:
181                 case MONO_TYPE_I1:
182                 case MONO_TYPE_U1:
183                 case MONO_TYPE_I2:
184                 case MONO_TYPE_U2:
185                 case MONO_TYPE_CHAR:
186                 case MONO_TYPE_I4:
187                 case MONO_TYPE_U4:
188                 case MONO_TYPE_I:
189                 case MONO_TYPE_U:
190                 case MONO_TYPE_CLASS:
191                 case MONO_TYPE_OBJECT:
192                 case MONO_TYPE_R4:
193                 case MONO_TYPE_R8:
194                 case MONO_TYPE_SZARRAY:
195                 case MONO_TYPE_ARRAY:
196                         *code_size += 8;
197                         break;
198                 case MONO_TYPE_STRING:
199                         *code_size += 8;
200                         if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && !runtime) {
201                                 *code_size += 16;
202                         }
203                         break;
204                 case MONO_TYPE_I8:
205                         *code_size += 12;
206                         break;
207                 case MONO_TYPE_VALUETYPE:
208                         if (sig->ret->data.klass->enumtype) {
209                                 simpletype = sig->ret->data.klass->enum_basetype->type;
210                                 goto enum_retvalue;
211                         }
212                         NOT_IMPLEMENTED ("valuetype");
213                         break;
214                 case MONO_TYPE_VOID:
215                         break;
216                 default:
217                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
218                 }
219         }
220
221         if (*strings) {
222                 /* space to keep parameters and prepared strings */
223                  *stack_size += 8;
224                  *code_size += 16;
225                  if (sig->hasthis) {
226                          *stack_size += 4;
227                          *code_size  += 12;
228                  }
229         }
230         /* align stack size to 16 */
231         DEBUG (printf ("      stack size: %d (%d)\n       code size: %d\n", (*stack_size + 15) & ~15, *stack_size, *code_size));
232         *stack_size = (*stack_size + 15) & ~15;
233
234 }
235
236 static inline guint8 *
237 emit_prolog (guint8 *p, MonoMethod *method, guint stack_size, guint strings)
238 {
239         /* function prolog */
240         ppc_stwu (p, ppc_r1, -stack_size, ppc_r1);     /* sp      <--- sp - stack_size, sp[0] <---- sp save sp, alloc stack */
241         ppc_mflr (p, ppc_r0);                          /* r0      <--- LR */
242         ppc_stw  (p, ppc_r31, stack_size - 4, ppc_r1); /* sp[+4]  <--- r31     save r31 */
243         ppc_stw  (p, ppc_r0, stack_size + 4, ppc_r1);  /* sp[-4]  <--- LR      save return address for "callme" */
244         ppc_mr   (p, ppc_r31, ppc_r1);                 /* r31     <--- sp */
245
246         /* handle our parameters */
247         if (strings) {
248                 ppc_stw  (p, ppc_r30, stack_size - 16, ppc_r1);
249                 ppc_stw  (p, ppc_r29, stack_size - 12, ppc_r1);
250                 if (method->signature->hasthis) {
251                         ppc_stw  (p, ppc_r28, 24, ppc_r1);
252                 }
253                 ppc_mr   (p, ppc_r30, ppc_r6);                        /* args */
254                 ppc_mr   (p, ppc_r29, ppc_r3);                        /* callme */
255                 if (method->signature->hasthis) {
256                         ppc_mr   (p, ppc_r28, ppc_r5);                /* this */
257                 }
258         } else {
259                 ppc_mr   (p, ppc_r12, ppc_r6);                        /* keep "arguments" in register */
260                 ppc_mr   (p, ppc_r0, ppc_r3);                         /* keep "callme" in register */
261         }
262         ppc_stw  (p, ppc_r4, stack_size - 12, ppc_r31);               /* preserve "retval", sp[+8] */
263
264         return p;
265 }
266
267 #define ARG_BASE strings ? ppc_r30 : ppc_r12
268 #define SAVE_4_IN_GENERIC_REGISTER \
269                         if (gr < GENERAL_REGS) { \
270                                 ppc_lwz  (p, ppc_r3 + gr, i*16, ARG_BASE); \
271                                 gr ++; \
272                         } else { \
273                                 ppc_lwz  (p, ppc_r11, i*16, ARG_BASE); \
274                                 ppc_stw  (p, ppc_r11, stack_par_pos, ppc_r1); \
275                                 stack_par_pos += 4; \
276                         }
277
278 inline static guint8*
279 emit_save_parameters (guint8 *p, MonoMethod *method, guint stack_size, guint strings, gint runtime)
280 {
281         MonoMethodSignature *sig;
282         guint i, fr, gr, act_strs, stack_par_pos;
283         guint32 simpletype;
284
285         fr = gr = 0;
286         act_strs = 0;
287         sig = method->signature;
288         stack_par_pos = 8;
289
290         if (strings) {
291                 for (i = 0; i < sig->param_count; ++i) {
292                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_STRING
293                             && !((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || runtime)) {
294                                 ppc_lis  (p, ppc_r0,     (guint32) mono_string_to_utf8 >> 16);
295                                 ppc_lwz  (p, ppc_r3, i*16, ppc_r30);
296                                 ppc_ori  (p, ppc_r0, ppc_r0, (guint32) mono_string_to_utf8 & 0xffff);
297                                 ppc_mtlr (p, ppc_r0);
298                                 ppc_blrl (p);
299                                 ppc_stw  (p, ppc_r3, stack_size - 24 - act_strs, ppc_r31);
300                                 act_strs += 4;
301                         }
302                 }
303         }
304
305         if (sig->hasthis) {
306                 ppc_mr (p, ppc_r3, ppc_r5);
307                 gr ++;
308         }
309
310         act_strs = 0;
311         for (i = 0; i < sig->param_count; ++i) {
312                 if (sig->params [i]->byref) {
313                         SAVE_4_IN_GENERIC_REGISTER;
314                         continue;
315                 }
316                 simpletype = sig->params [i]->type;
317         enum_calc_size:
318                 switch (simpletype) {
319                 case MONO_TYPE_BOOLEAN:
320                 case MONO_TYPE_I1:
321                 case MONO_TYPE_U1:
322                 case MONO_TYPE_I2:
323                 case MONO_TYPE_U2:
324                 case MONO_TYPE_CHAR:
325                 case MONO_TYPE_I4:
326                 case MONO_TYPE_U4:
327                 case MONO_TYPE_I:
328                 case MONO_TYPE_U:
329                 case MONO_TYPE_PTR:
330                 case MONO_TYPE_SZARRAY:
331                 case MONO_TYPE_CLASS:
332                 case MONO_TYPE_OBJECT:
333                         SAVE_4_IN_GENERIC_REGISTER;
334                         break;
335                 case MONO_TYPE_VALUETYPE:
336                         if (sig->params [i]->data.klass->enumtype) {
337                                 simpletype = sig->params [i]->data.klass->enum_basetype->type;
338                                 goto enum_calc_size;
339                         }
340                         if (mono_class_value_size (sig->params [i]->data.klass, NULL) != 4)
341                                 g_error ("can only marshal enums, not generic structures (size: %d)",
342                                          mono_class_value_size (sig->params [i]->data.klass, NULL));
343                         if (gr < GENERAL_REGS) {
344                                 ppc_lwz  (p, ppc_r3 + gr, i*16, ARG_BASE);
345                                 ppc_lwz  (p, ppc_r3 + gr, 0, ppc_r3 + gr);
346                                 gr ++;
347                         } else {
348                                 NOT_IMPLEMENTED ("save value type on stack");
349                         }
350                         break;
351                 case MONO_TYPE_STRING:
352                         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || runtime) {
353                                 SAVE_4_IN_GENERIC_REGISTER;
354                         } else {
355                                 if (gr < 8) {
356                                         ppc_lwz (p, ppc_r3 + gr, stack_size - 24 - act_strs, ppc_r31);
357                                         gr ++;
358                                         act_strs += 4;
359                                 } else
360                                         NOT_IMPLEMENTED ("string on stack");
361                         }
362                         break;
363                 case MONO_TYPE_I8:
364                         if (gr < 7) {
365                                 if (gr & 1)
366                                         gr ++;
367                                 ppc_lwz  (p, ppc_r3 + gr, i*16, ARG_BASE);
368                                 gr ++;
369                                 ppc_lwz  (p, ppc_r3 + gr, i*16 + 4, ARG_BASE);
370                                 gr ++;
371                         } else {
372                                 NOT_IMPLEMENTED ("i8 on stack");
373                         }
374                         break;
375                 case MONO_TYPE_R4:
376                         if (fr < 7) {
377                                 ppc_lfs  (p, ppc_f1 + fr, i*16, ARG_BASE);
378                                 fr ++;
379                         } else {
380                                 NOT_IMPLEMENTED ("r4 on stack");
381                         }
382                         break;
383                 case MONO_TYPE_R8:
384                         if (fr < 7) {
385                                 ppc_lfd  (p, ppc_f1 + fr, i*16, ARG_BASE);
386                                 fr ++;
387                         } else {
388                                 NOT_IMPLEMENTED ("r8 on stack");
389                         }
390                         break;
391                 default:
392                         g_error ("Can't trampoline 0x%x", sig->params [i]->type);
393                 }
394         }
395
396         return p;
397 }
398
399 static inline guint8 *
400 alloc_code_memory (guint code_size)
401 {
402         guint8 *p;
403
404 #ifdef NEED_MPROTECT
405         p = g_malloc (code_size + PAGESIZE - 1);
406
407         /* Align to a multiple of PAGESIZE, assumed to be a power of two */
408         p = (char *)(((int) p + PAGESIZE-1) & ~(PAGESIZE-1));
409 #else
410         p = g_malloc (code_size);
411 #endif
412         DEBUG (printf ("           align: %p (%d)\n", p, (guint)p % 4));
413
414         return p;
415 }
416
417 /* static MonoString*
418 mono_string_new_wrapper (const char *text)
419 {
420         return text ? mono_string_new (mono_domain_get (), text) : NULL;
421 } */
422
423 static inline guint8 *
424 emit_call_and_store_retval (guint8 *p, MonoMethod *method, guint stack_size, guint strings, gint runtime)
425 {
426         MonoMethodSignature *sig = method->signature;
427         guint32 simpletype;
428
429         /* call "callme" */
430         ppc_mtlr (p, strings ? ppc_r29 : ppc_r0);
431         ppc_blrl (p);
432
433         /* get return value */
434         if (sig->ret->byref ||
435             (method->klass == mono_defaults.string_class &&
436              *method->name == '.' && !strcmp (method->name, ".ctor"))) {
437                 ppc_lwz  (p, ppc_r9, stack_size - 12, ppc_r31);        /* load "retval" address */
438                 ppc_stw  (p, ppc_r3, 0, ppc_r9);                       /* save return value (r3) to "retval" */
439         } else {
440                 simpletype = sig->ret->type;
441 enum_retvalue:
442                 switch (simpletype) {
443                 case MONO_TYPE_BOOLEAN:
444                 case MONO_TYPE_I1:
445                 case MONO_TYPE_U1:
446                         ppc_lwz  (p, ppc_r9, stack_size - 12, ppc_r31);        /* load "retval" address */
447                         ppc_stb  (p, ppc_r3, 0, ppc_r9);                       /* save return value (r3) to "retval" */
448                         break;
449                 case MONO_TYPE_I2:
450                 case MONO_TYPE_U2:
451                 case MONO_TYPE_CHAR:
452                         ppc_lwz  (p, ppc_r9, stack_size - 12, ppc_r31);        /* load "retval" address */
453                         ppc_sth  (p, ppc_r3, 0, ppc_r9);                       /* save return value (r3) to "retval" */
454                         break;
455                 case MONO_TYPE_I4:
456                 case MONO_TYPE_U4:
457                 case MONO_TYPE_I:
458                 case MONO_TYPE_U:
459                 case MONO_TYPE_CLASS:
460                 case MONO_TYPE_OBJECT:
461                 case MONO_TYPE_SZARRAY:
462                 case MONO_TYPE_ARRAY:
463                         ppc_lwz  (p, ppc_r9, stack_size - 12, ppc_r31);        /* load "retval" address */
464                         ppc_stw  (p, ppc_r3, 0, ppc_r9);                       /* save return value (r3) to "retval" */
465                         break;
466                 case MONO_TYPE_STRING:
467                         if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && !runtime) {
468                                 ppc_lis  (p, ppc_r0,     (guint32) mono_string_new_wrapper >> 16);
469                                 ppc_ori  (p, ppc_r0, ppc_r0, (guint32) mono_string_new_wrapper & 0xffff);
470                                 ppc_mtlr (p, ppc_r0);
471                                 ppc_blrl (p);
472                         }
473
474                         ppc_lwz  (p, ppc_r9, stack_size - 12, ppc_r31);        /* load "retval" address */
475                         ppc_stw  (p, ppc_r3, 0, ppc_r9);                       /* save return value (r3) to "retval" */
476
477                         break;
478                 case MONO_TYPE_R4:
479                         ppc_lwz  (p, ppc_r9, stack_size - 12, ppc_r31);        /* load "retval" address */
480                         ppc_stfs (p, ppc_f1, 0, ppc_r9);                       /* save return value (f1) to "retval" */
481                         break;
482                 case MONO_TYPE_R8:
483                         ppc_lwz  (p, ppc_r9, stack_size - 12, ppc_r31);        /* load "retval" address */
484                         ppc_stfd (p, ppc_f1, 0, ppc_r9);                       /* save return value (f1) to "retval" */
485                         break;
486                 case MONO_TYPE_I8:
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         DEBUG (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         DEBUG (printf ("emited code size: %d\n", p - code_buffer));
578         flush_icache (code_buffer, p - code_buffer);
579
580         DEBUG (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         DEBUG (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         DEBUG (printf ("emited code size: %d\n", p - code_buffer));
792         flush_icache (code_buffer, p - code_buffer);
793
794         DEBUG (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 }