2 * Create trampolines to invoke arbitrary functions.
4 * Copyright (C) Radek Doulik
11 #include "ppc-codegen.h"
12 #include "mono/metadata/class.h"
13 #include "mono/metadata/tabledefs.h"
14 #include "mono/interpreter/interp.h"
15 #include "mono/metadata/appdomain.h"
19 #include <limits.h> /* for PAGESIZE */
28 fake_func (gpointer (*callme)(gpointer), stackval *retval, void *this_obj, stackval *arguments)
30 guint32 i = 0xc002becd;
32 callme = (gpointer) 0x100fabcd;
34 *(gpointer*)retval = (gpointer)(*callme) (arguments [0].data.p, arguments [1].data.p, arguments [2].data.p);
35 *(gdouble*) retval = (gdouble)(*callme) (arguments [0].data.f);
37 return (gpointer) (*callme) (((MonoType *)arguments [0]. data.p)->data.klass);
40 #define MIN_CACHE_LINE 8
43 flush_icache (guint8 *code, guint size)
49 for (i = 0; i < size; i += MIN_CACHE_LINE, p += MIN_CACHE_LINE) {
50 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
54 for (i = 0; i < size; i += MIN_CACHE_LINE, p += MIN_CACHE_LINE) {
55 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
62 disassemble (guint8 *code, int size)
66 const char *tmp = g_getenv("TMP");
73 as_file = g_strdup_printf ("%s/test.s", tmp);
75 if (!(ofd = fopen (as_file, "w")))
76 g_assert_not_reached ();
78 fprintf (ofd, "tmp:\n");
80 for (i = 0; i < size; ++i)
81 fprintf (ofd, ".byte %d\n", (unsigned int) code [i]);
85 #define DIS_CMD "otool -V -v -t"
87 #define DIS_CMD "objdump -d"
89 o_file = g_strdup_printf ("%s/test.o", tmp);
90 cmd = g_strdup_printf ("as %s -o %s", as_file, o_file);
93 cmd = g_strdup_printf (DIS_CMD " %s", o_file);
101 #define NOT_IMPLEMENTED(x) \
102 g_error ("FIXME: %s is not yet implemented. (trampoline)", x);
108 #define GENERAL_REGS 8
110 #define MINIMAL_STACK_SIZE 10
111 #define ALWAYS_ON_STACK(s) s
112 #define FP_ALSO_IN_REG(s) s
113 #define RET_ADDR_OFFSET 8
114 #define STACK_PARAM_OFFSET 24
116 #define MINIMAL_STACK_SIZE 5
117 #define ALWAYS_ON_STACK(s)
118 #define FP_ALSO_IN_REG(s) s
119 #define ALIGN_DOUBLES
120 #define RET_ADDR_OFFSET 4
121 #define STACK_PARAM_OFFSET 8
125 add_general (guint *gr, guint *stack_size, guint *code_size, gboolean simple)
128 if (*gr >= GENERAL_REGS) {
130 *code_size += 8; /* load from stack, save on stack */
132 ALWAYS_ON_STACK (*stack_size += 4);
133 *code_size += 4; /* load from stack */
136 if (*gr >= GENERAL_REGS - 1) {
139 *stack_size += (*stack_size % 8);
141 *code_size += 16; /* 2x load from stack, 2x save to stack */
143 ALWAYS_ON_STACK (*stack_size += 8);
144 *code_size += 8; /* 2x load from stack */
156 calculate_sizes (MonoMethodSignature *sig, guint *stack_size, guint *code_size, gboolean string_ctor, gboolean *use_memcpy)
162 *stack_size = MINIMAL_STACK_SIZE*4;
163 *code_size = (PROLOG_INS + CALL_INS + EPILOG_INS)*4;
166 add_general (&gr, stack_size, code_size, TRUE);
168 DEBUG(printf("params: %d\n", sig->param_count));
169 for (i = 0; i < sig->param_count; ++i) {
170 DEBUG(printf("param %d: ", i));
171 if (sig->params [i]->byref) {
172 DEBUG(printf("byref\n"));
173 add_general (&gr, stack_size, code_size, TRUE);
176 simpletype = sig->params [i]->type;
178 switch (simpletype) {
179 case MONO_TYPE_BOOLEAN:
190 case MONO_TYPE_CLASS:
191 case MONO_TYPE_OBJECT:
192 case MONO_TYPE_STRING:
193 add_general (&gr, stack_size, code_size, TRUE);
195 case MONO_TYPE_SZARRAY:
196 add_general (&gr, stack_size, code_size, TRUE);
199 case MONO_TYPE_VALUETYPE: {
201 if (sig->params [i]->data.klass->enumtype) {
202 simpletype = sig->params [i]->data.klass->enum_basetype->type;
205 size = mono_class_value_size (sig->params [i]->data.klass, NULL);
207 DEBUG(printf ("copy %d bytes struct on stack\n",
208 mono_class_value_size (sig->params [i]->data.klass, NULL)));
211 *stack_size += (size + 3) & (~3);
212 if (gr > GENERAL_REGS) {
217 DEBUG(printf ("load %d bytes struct\n",
218 mono_class_value_size (sig->params [i]->data.klass, NULL)));
219 add_general (&gr, stack_size, code_size, TRUE);
225 add_general (&gr, stack_size, code_size, FALSE);
231 FP_ALSO_IN_REG (gr ++);
232 ALWAYS_ON_STACK (*stack_size += 4);
234 NOT_IMPLEMENTED ("R4 arg");
241 FP_ALSO_IN_REG (gr += 2);
242 ALWAYS_ON_STACK (*stack_size += 8);
244 NOT_IMPLEMENTED ("R8 arg");
248 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
252 if (sig->ret->byref || string_ctor) {
255 simpletype = sig->ret->type;
257 switch (simpletype) {
258 case MONO_TYPE_BOOLEAN:
268 case MONO_TYPE_CLASS:
269 case MONO_TYPE_OBJECT:
272 case MONO_TYPE_SZARRAY:
273 case MONO_TYPE_ARRAY:
274 case MONO_TYPE_STRING:
280 case MONO_TYPE_VALUETYPE:
281 if (sig->ret->data.klass->enumtype) {
282 simpletype = sig->ret->data.klass->enum_basetype->type;
290 g_error ("Can't handle as return value 0x%x", sig->ret->type);
295 *stack_size += 2*4; /* for r14, r15 */
298 *stack_size += 4; /* for r16 */
303 /* align stack size to 16 */
304 DEBUG (printf (" stack size: %d (%d)\n code size: %d\n", (*stack_size + 15) & ~15, *stack_size, *code_size));
305 *stack_size = (*stack_size + 15) & ~15;
308 static inline guint8 *
309 emit_prolog (guint8 *p, MonoMethodSignature *sig, guint stack_size)
311 /* function prolog */
312 ppc_stwu (p, ppc_r1, -stack_size, ppc_r1); /* sp <--- sp - stack_size, sp[0] <---- sp save sp, alloc stack */
313 ppc_mflr (p, ppc_r0); /* r0 <--- LR */
314 ppc_stw (p, ppc_r31, stack_size - 4, ppc_r1); /* sp[+4] <--- r31 save r31 */
315 ppc_stw (p, ppc_r0, stack_size + RET_ADDR_OFFSET, ppc_r1); /* sp[-4] <--- LR save return address for "callme" */
316 ppc_mr (p, ppc_r31, ppc_r1); /* r31 <--- sp */
321 #define ARG_BASE ppc_r12
322 #define ARG_SIZE sizeof (stackval)
323 #define SAVE_4_IN_GENERIC_REGISTER \
324 if (gr < GENERAL_REGS) { \
325 ppc_lwz (p, ppc_r3 + gr, i*ARG_SIZE, ARG_BASE); \
327 ALWAYS_ON_STACK (stack_par_pos += 4); \
329 ppc_lwz (p, ppc_r11, i*ARG_SIZE, ARG_BASE); \
330 ppc_stw (p, ppc_r11, stack_par_pos, ppc_r1); \
331 stack_par_pos += 4; \
333 #define SAVE_4_VAL_IN_GENERIC_REGISTER \
334 if (gr < GENERAL_REGS) { \
335 ppc_lwz (p, ppc_r3 + gr, i*ARG_SIZE, ARG_BASE); \
336 ppc_lwz (p, ppc_r3 + gr, 0, ppc_r3 + gr); \
338 ALWAYS_ON_STACK (stack_par_pos += 4); \
340 ppc_lwz (p, ppc_r11, i*ARG_SIZE, ARG_BASE); \
341 ppc_lwz (p, ppc_r11, 0, ppc_r11); \
342 ppc_stw (p, ppc_r11, stack_par_pos, ppc_r1); \
343 stack_par_pos += 4; \
346 inline static guint8*
347 emit_save_parameters (guint8 *p, MonoMethodSignature *sig, guint stack_size, gboolean use_memcpy)
349 guint i, fr, gr, stack_par_pos, struct_pos, cur_struct_pos;
353 stack_par_pos = STACK_PARAM_OFFSET;
355 ppc_stw (p, ppc_r4, stack_size - 12, ppc_r31); /* preserve "retval", sp[+8] */
358 ppc_stw (p, ppc_r14, stack_size - 16, ppc_r31); /* save r14 */
359 ppc_stw (p, ppc_r15, stack_size - 20, ppc_r31); /* save r15 */
360 ppc_mr (p, ppc_r14, ppc_r3); /* keep "callme" in register */
361 ppc_mr (p, ppc_r15, ppc_r6); /* keep "arguments" in register */
363 ppc_mr (p, ppc_r12, ppc_r6); /* keep "arguments" in register */
364 ppc_mr (p, ppc_r0, ppc_r3); /* keep "callme" in register */
369 ppc_stw (p, ppc_r16, stack_size - 24, ppc_r31); /* save r16 */
370 ppc_mr (p, ppc_r16, ppc_r5);
372 ppc_mr (p, ppc_r3, ppc_r5);
374 ALWAYS_ON_STACK (stack_par_pos += 4);
378 cur_struct_pos = struct_pos = stack_par_pos;
379 for (i = 0; i < sig->param_count; ++i) {
380 if (sig->params [i]->byref)
382 if (sig->params [i]->type == MONO_TYPE_VALUETYPE && !sig->params [i]->data.klass->enumtype) {
385 size = mono_class_value_size (sig->params [i]->data.klass, NULL);
388 ppc_addi (p, ppc_r3, ppc_r1, stack_par_pos);
389 ppc_lwz (p, ppc_r4, i*16, ppc_r15);
390 /* FIXME check if size > 0xffff */
391 ppc_li (p, ppc_r5, size & 0xffff);
392 ppc_lis (p, ppc_r0, (guint32) memcpy >> 16);
393 ppc_ori (p, ppc_r0, ppc_r0, (guint32) memcpy & 0xffff);
394 ppc_mtlr (p, ppc_r0);
396 stack_par_pos += (size + 3) & (~3);
402 ppc_mr (p, ppc_r3, ppc_r16);
403 ppc_lwz (p, ppc_r16, stack_size - 24, ppc_r31); /* restore r16 */
405 ppc_mr (p, ppc_r0, ppc_r14);
406 ppc_mr (p, ppc_r12, ppc_r15);
407 ppc_lwz (p, ppc_r14, stack_size - 16, ppc_r31); /* restore r14 */
408 ppc_lwz (p, ppc_r15, stack_size - 20, ppc_r31); /* restore r15 */
411 if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref) {
412 MonoClass *klass = sig->ret->data.klass;
413 if (!klass->enumtype) {
414 gint size = mono_class_native_size (klass, NULL);
416 DEBUG(printf ("retval value type size: %d\n", size));
418 ppc_lwz (p, ppc_r3, stack_size - 12, ppc_r31);
419 ppc_lwz (p, ppc_r3, 0, ppc_r3);
421 ALWAYS_ON_STACK (stack_par_pos += 4);
423 NOT_IMPLEMENTED ("retval valuetype <= 8 bytes");
428 for (i = 0; i < sig->param_count; ++i) {
429 if (sig->params [i]->byref) {
430 SAVE_4_IN_GENERIC_REGISTER;
433 simpletype = sig->params [i]->type;
435 switch (simpletype) {
436 case MONO_TYPE_BOOLEAN:
447 case MONO_TYPE_CLASS:
448 case MONO_TYPE_OBJECT:
449 case MONO_TYPE_STRING:
450 case MONO_TYPE_SZARRAY:
451 SAVE_4_IN_GENERIC_REGISTER;
453 case MONO_TYPE_VALUETYPE: {
455 if (sig->params [i]->data.klass->enumtype) {
456 simpletype = sig->params [i]->data.klass->enum_basetype->type;
459 size = mono_class_value_size (sig->params [i]->data.klass, NULL);
461 SAVE_4_VAL_IN_GENERIC_REGISTER;
463 if (gr < GENERAL_REGS) {
464 ppc_addi (p, ppc_r3 + gr, ppc_r1, cur_struct_pos);
467 ppc_lwz (p, ppc_r11, cur_struct_pos, ppc_r1);
468 ppc_stw (p, ppc_r11, stack_par_pos, ppc_r1);
471 cur_struct_pos += (size + 3) & (~3);
476 DEBUG(printf("Mono_Type_i8. gr = %d, arg_base = %d\n", gr, ARG_BASE));
482 ppc_lwz (p, ppc_r3 + gr, i*ARG_SIZE, ARG_BASE);
483 ppc_lwz (p, ppc_r3 + gr + 1, i*ARG_SIZE + 4, ARG_BASE);
484 ALWAYS_ON_STACK (stack_par_pos += 8);
485 } else if (gr == 7) {
486 ppc_lwz (p, ppc_r3 + gr, i*ARG_SIZE, ARG_BASE);
487 ppc_lwz (p, ppc_r11, i*ARG_SIZE + 4, ARG_BASE);
488 ppc_stw (p, ppc_r11, stack_par_pos + 4, ppc_r1);
491 ppc_lwz (p, ppc_r11, i*ARG_SIZE, ARG_BASE);
492 ppc_stw (p, ppc_r11, stack_par_pos, ppc_r1);
493 ppc_lwz (p, ppc_r11, i*ARG_SIZE + 4, ARG_BASE);
494 ppc_stw (p, ppc_r11, stack_par_pos + 4, ppc_r1);
501 ppc_lfs (p, ppc_f1 + fr, i*ARG_SIZE, ARG_BASE);
503 FP_ALSO_IN_REG (gr ++);
504 ALWAYS_ON_STACK (stack_par_pos += 4);
506 NOT_IMPLEMENTED ("r4 on stack");
511 ppc_lfd (p, ppc_f1 + fr, i*ARG_SIZE, ARG_BASE);
513 FP_ALSO_IN_REG (gr += 2);
514 ALWAYS_ON_STACK (stack_par_pos += 8);
516 NOT_IMPLEMENTED ("r8 on stack");
520 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
527 static inline guint8 *
528 alloc_code_memory (guint code_size)
533 p = g_malloc (code_size + PAGESIZE - 1);
535 /* Align to a multiple of PAGESIZE, assumed to be a power of two */
536 p = (char *)(((int) p + PAGESIZE-1) & ~(PAGESIZE-1));
538 p = g_malloc (code_size);
540 DEBUG (printf (" align: %p (%d)\n", p, (guint)p % 4));
545 /* static MonoString*
546 mono_string_new_wrapper (const char *text)
548 return text ? mono_string_new (mono_domain_get (), text) : NULL;
551 static inline guint8 *
552 emit_call_and_store_retval (guint8 *p, MonoMethodSignature *sig, guint stack_size, gboolean string_ctor)
557 ppc_mtlr (p, ppc_r0);
560 /* get return value */
561 if (sig->ret->byref || string_ctor) {
562 ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */
563 ppc_stw (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
565 simpletype = sig->ret->type;
567 switch (simpletype) {
568 case MONO_TYPE_BOOLEAN:
571 ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */
572 ppc_stb (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
577 ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */
578 ppc_sth (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
584 case MONO_TYPE_CLASS:
585 case MONO_TYPE_OBJECT:
586 case MONO_TYPE_SZARRAY:
587 case MONO_TYPE_ARRAY:
588 case MONO_TYPE_STRING:
589 ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */
590 ppc_stw (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
593 ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */
594 ppc_stfs (p, ppc_f1, 0, ppc_r9); /* save return value (f1) to "retval" */
597 ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */
598 ppc_stfd (p, ppc_f1, 0, ppc_r9); /* save return value (f1) to "retval" */
601 ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */
602 ppc_stw (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
603 ppc_stw (p, ppc_r4, 4, ppc_r9); /* save return value (r3) to "retval" */
605 case MONO_TYPE_VALUETYPE:
606 if (sig->ret->data.klass->enumtype) {
607 simpletype = sig->ret->data.klass->enum_basetype->type;
614 g_error ("Can't handle as return value 0x%x", sig->ret->type);
621 static inline guint8 *
622 emit_epilog (guint8 *p, MonoMethodSignature *sig, guint stack_size)
624 /* function epilog */
625 ppc_lwz (p, ppc_r11, 0, ppc_r1); /* r11 <--- sp[0] load backchain from caller's function */
626 ppc_lwz (p, ppc_r0, RET_ADDR_OFFSET, ppc_r11); /* r0 <--- r11[4] load return address */
627 ppc_mtlr (p, ppc_r0); /* LR <--- r0 set return address */
628 ppc_lwz (p, ppc_r31, -4, ppc_r11); /* r31 <--- r11[-4] restore r31 */
629 ppc_mr (p, ppc_r1, ppc_r11); /* sp <--- r11 restore stack */
630 ppc_blr (p); /* return */
636 mono_arch_create_trampoline (MonoMethodSignature *sig, gboolean string_ctor)
638 guint8 *p, *code_buffer;
639 guint stack_size, code_size;
640 gboolean use_memcpy = FALSE;
642 DEBUG (printf ("\nPInvoke [start emiting]\n"));
643 calculate_sizes (sig, &stack_size, &code_size, string_ctor, &use_memcpy);
645 p = code_buffer = alloc_code_memory (code_size);
646 p = emit_prolog (p, sig, stack_size);
647 p = emit_save_parameters (p, sig, stack_size, use_memcpy);
648 p = emit_call_and_store_retval (p, sig, stack_size, string_ctor);
649 p = emit_epilog (p, sig, stack_size);
653 printf (".text\n.align 4\n.globl main\n.type main,@function\nmain:\n");
654 for (cp = code_buffer; cp < p; cp++) {
655 printf (".byte 0x%x\n", *cp);
660 if (mprotect (code_buffer, 1024, PROT_READ | PROT_WRITE | PROT_EXEC)) {
661 g_error ("Cannot mprotect trampoline\n");
665 DEBUG (printf ("emited code size: %d\n", p - code_buffer));
666 flush_icache (code_buffer, p - code_buffer);
668 DEBUG (printf ("PInvoke [end emiting]\n"));
670 return (MonoPIFunc) code_buffer;
671 /* return fake_func; */
676 #define MINV_POS 40 /* MonoInvocation structure offset on stack - STACK_PARAM_OFFSET + 4 pointer args for stackval_from_data */
678 #define MINV_POS 8 /* MonoInvocation structure offset on stack */
680 #define STACK_POS (MINV_POS - sizeof (stackval) * sig->param_count)
682 #define TYPE_OFFSET (G_STRUCT_OFFSET (stackval, type))
685 * Returns a pointer to a native function that can be used to
686 * call the specified method.
687 * The function created will receive the arguments according
688 * to the call convention specified in the method.
689 * This function works by creating a MonoInvocation structure,
690 * filling the fields in and calling ves_exec_method on it.
691 * Still need to figure out how to handle the exception stuff
692 * across the managed/unmanaged boundary.
695 mono_arch_create_method_pointer (MonoMethod *method)
697 MonoMethodSignature *sig;
699 guint8 *p, *code_buffer;
700 guint i, align = 0, code_size, stack_size, stackval_arg_pos, local_pos, local_start, reg_param = 0, stack_param,
709 sig = mono_method_signature (method);
711 p = code_buffer = g_malloc (code_size);
713 DEBUG (printf ("\nDelegate [start emiting] %s\n", mono_method_get_name (method)));
716 ppc_stwu (p, ppc_r1, -stack_size, ppc_r1); /* sp <--- sp - stack_size, sp[0] <---- sp save sp, alloc stack */
717 ppc_mflr (p, ppc_r0); /* r0 <--- LR */
718 ppc_stw (p, ppc_r31, stack_size - 4, ppc_r1); /* sp[+4] <--- r31 save r31 */
719 ppc_stw (p, ppc_r0, stack_size + RET_ADDR_OFFSET, ppc_r1); /* sp[-4] <--- LR save return address for "callme" */
720 ppc_mr (p, ppc_r31, ppc_r1); /* r31 <--- sp */
722 /* let's fill MonoInvocation */
723 /* first zero some fields */
724 ppc_li (p, ppc_r0, 0);
725 ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex)), ppc_r31);
726 ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex_handler)), ppc_r31);
727 ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, parent)), ppc_r31);
729 /* set method pointer */
730 ppc_lis (p, ppc_r0, (guint32) method >> 16);
731 ppc_ori (p, ppc_r0, ppc_r0, (guint32) method & 0xffff);
732 ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, method)), ppc_r31);
734 local_start = local_pos = MINV_POS + sizeof (MonoInvocation) + (sig->param_count + 1) * sizeof (stackval);
737 ppc_stw (p, ppc_r3, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj)), ppc_r31);
741 if (sig->param_count) {
742 gint save_count = MIN (8, sig->param_count + sig->hasthis);
743 for (i = reg_param; i < save_count; i ++) {
744 ppc_stw (p, ppc_r3 + i, local_pos, ppc_r31);
746 DEBUG (printf ("save r%d\n", 4 + i));
750 /* prepare space for valuetypes */
752 vtbuf = alloca (sizeof(int)*sig->param_count);
754 for (i = 0; i < sig->param_count; i++) {
755 MonoType *type = sig->params [i];
757 if (type->type == MONO_TYPE_VALUETYPE) {
758 MonoClass *klass = type->data.klass;
763 size = mono_class_native_size (klass, &align);
765 cpos &= ~(align - 1);
775 /* set MonoInvocation::stack_args */
776 stackval_arg_pos = MINV_POS + sizeof (MonoInvocation);
777 ppc_addi (p, ppc_r0, ppc_r31, stackval_arg_pos);
778 ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, stack_args)), ppc_r31);
780 /* add stackval arguments */
781 for (i = 0; i < sig->param_count; ++i) {
783 ppc_addi (p, ppc_r5, ppc_r31, local_start + i*4);
786 ppc_addi (p, ppc_r5, stack_size + 8 + stack_param, ppc_r31);
789 ppc_lis (p, ppc_r3, (guint32) sig->params [i] >> 16);
791 if (vtbuf [i] >= 0) {
792 ppc_addi (p, ppc_r4, ppc_r31, vt_cur);
793 ppc_stw (p, ppc_r4, stackval_arg_pos, ppc_r31);
794 ppc_addi (p, ppc_r4, ppc_r31, stackval_arg_pos);
795 ppc_lwz (p, ppc_r5, 0, ppc_r5);
798 ppc_addi (p, ppc_r4, ppc_r31, stackval_arg_pos);
800 ppc_ori (p, ppc_r3, ppc_r3, (guint32) sig->params [i] & 0xffff);
801 ppc_lis (p, ppc_r0, (guint32) stackval_from_data >> 16);
802 ppc_li (p, ppc_r6, sig->pinvoke);
803 ppc_ori (p, ppc_r0, ppc_r0, (guint32) stackval_from_data & 0xffff);
804 ppc_mtlr (p, ppc_r0);
807 stackval_arg_pos += sizeof (stackval);
810 /* return value storage */
811 if (sig->param_count) {
812 ppc_addi (p, ppc_r0, ppc_r31, stackval_arg_pos);
814 ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, retval)), ppc_r31);
816 /* call ves_exec_method */
817 ppc_lis (p, ppc_r0, (guint32) ves_exec_method >> 16);
818 ppc_addi (p, ppc_r3, ppc_r31, MINV_POS);
819 ppc_ori (p, ppc_r0, ppc_r0, (guint32) ves_exec_method & 0xffff);
820 ppc_mtlr (p, ppc_r0);
823 /* move retval from stackval to proper place (r3/r4/...) */
824 if (sig->ret->byref) {
825 DEBUG (printf ("ret by ref\n"));
826 ppc_lwz (p, ppc_r3, stackval_arg_pos, ppc_r31);
829 switch (sig->ret->type) {
832 case MONO_TYPE_BOOLEAN:
835 ppc_lbz (p, ppc_r3, stackval_arg_pos, ppc_r31);
839 ppc_lhz (p, ppc_r3, stackval_arg_pos, ppc_r31);
845 case MONO_TYPE_OBJECT:
846 case MONO_TYPE_STRING:
847 case MONO_TYPE_CLASS:
848 ppc_lwz (p, ppc_r3, stackval_arg_pos, ppc_r31);
851 ppc_lwz (p, ppc_r3, stackval_arg_pos, ppc_r31);
852 ppc_lwz (p, ppc_r4, stackval_arg_pos + 4, ppc_r31);
855 ppc_lfs (p, ppc_f1, stackval_arg_pos, ppc_r31);
858 ppc_lfd (p, ppc_f1, stackval_arg_pos, ppc_r31);
860 case MONO_TYPE_VALUETYPE:
861 if (sig->ret->data.klass->enumtype) {
862 simpletype = sig->ret->data.klass->enum_basetype->type;
865 NOT_IMPLEMENTED ("value type as ret val from delegate");
868 g_error ("Type 0x%x not handled yet in thunk creation", sig->ret->type);
874 ppc_lwz (p, ppc_r11, 0, ppc_r1); /* r11 <--- sp[0] load backchain from caller's function */
875 ppc_lwz (p, ppc_r0, RET_ADDR_OFFSET, ppc_r11); /* r0 <--- r11[4] load return address */
876 ppc_mtlr (p, ppc_r0); /* LR <--- r0 set return address */
877 ppc_lwz (p, ppc_r31, -4, ppc_r11); /* r31 <--- r11[-4] restore r31 */
878 ppc_mr (p, ppc_r1, ppc_r11); /* sp <--- r11 restore stack */
879 ppc_blr (p); /* return */
881 DEBUG (printf ("emited code size: %d\n", p - code_buffer));
882 DEBUG (disassemble (code_buffer, p - code_buffer));
883 flush_icache (code_buffer, p - code_buffer);
885 DEBUG (printf ("Delegate [end emiting]\n"));
887 ji = g_new0 (MonoJitInfo, 1);
889 ji->code_size = p - code_buffer;
890 ji->code_start = code_buffer;
892 mono_jit_info_table_add (mono_get_root_domain (), ji);
894 return ji->code_start;