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