2 * Create trampolines to invoke arbitrary functions.
4 * Copyright (C) Radek Doulik
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"
18 #include <limits.h> /* for PAGESIZE */
27 fake_func (gpointer (*callme)(gpointer), stackval *retval, void *this_obj, stackval *arguments)
29 guint32 i = 0xc002becd;
31 callme = (gpointer) 0x100fabcd;
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);
36 return (gpointer) (*callme) (((MonoType *)arguments [0]. data.p)->data.klass);
39 #define MIN_CACHE_LINE 8
42 flush_icache (guint8 *code, guint size)
48 for (i = 0; i < size; i += MIN_CACHE_LINE, p += MIN_CACHE_LINE) {
49 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
53 for (i = 0; i < size; i += MIN_CACHE_LINE, p += MIN_CACHE_LINE) {
54 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
60 #define NOT_IMPLEMENTED(x) \
61 g_error ("FIXME: %s is not yet implemented. (trampoline)", x);
66 #define MINIMAL_STACK_SIZE 5
68 #define GENERAL_REGS 8
71 add_general (guint *gr, guint *stack_size, guint *code_size, gboolean simple)
74 if (*gr >= GENERAL_REGS) {
76 *code_size += 8; /* load from stack, save on stack */
78 *code_size += 4; /* load from stack */
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 */
85 *code_size += 16; /* 2x load from stack */
95 calculate_sizes (MonoMethod *method, guint *stack_size, guint *code_size, guint *strings, gint runtime)
97 MonoMethodSignature *sig;
102 *stack_size = MINIMAL_STACK_SIZE*4;
103 *code_size = (PROLOG_INS + CALL_INS + EPILOG_INS)*4;
106 sig = method->signature;
108 add_general (&gr, stack_size, code_size, TRUE);
111 for (i = 0; i < sig->param_count; ++i) {
112 if (sig->params [i]->byref) {
113 add_general (&gr, stack_size, code_size, TRUE);
116 simpletype = sig->params [i]->type;
118 switch (simpletype) {
119 case MONO_TYPE_BOOLEAN:
130 case MONO_TYPE_SZARRAY:
131 case MONO_TYPE_CLASS:
132 case MONO_TYPE_OBJECT:
133 add_general (&gr, stack_size, code_size, TRUE);
135 case MONO_TYPE_VALUETYPE:
136 if (sig->params [i]->data.klass->enumtype) {
137 simpletype = sig->params [i]->data.klass->enum_basetype->type;
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);
146 case MONO_TYPE_STRING:
147 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || runtime) {
148 add_general (&gr, stack_size, code_size, TRUE);
156 add_general (&gr, stack_size, code_size, FALSE);
164 NOT_IMPLEMENTED ("R8 arg");
168 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
172 if (sig->ret->byref ||
173 (method->klass == mono_defaults.string_class &&
174 *method->name == '.' && !strcmp (method->name, ".ctor"))) {
177 simpletype = sig->ret->type;
179 switch (simpletype) {
180 case MONO_TYPE_BOOLEAN:
190 case MONO_TYPE_CLASS:
191 case MONO_TYPE_OBJECT:
194 case MONO_TYPE_SZARRAY:
195 case MONO_TYPE_ARRAY:
198 case MONO_TYPE_STRING:
200 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && !runtime) {
207 case MONO_TYPE_VALUETYPE:
208 if (sig->ret->data.klass->enumtype) {
209 simpletype = sig->ret->data.klass->enum_basetype->type;
212 NOT_IMPLEMENTED ("valuetype");
217 g_error ("Can't handle as return value 0x%x", sig->ret->type);
222 /* space to keep parameters and prepared strings */
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;
236 static inline guint8 *
237 emit_prolog (guint8 *p, MonoMethod *method, guint stack_size, guint strings)
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 */
246 /* handle our parameters */
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);
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 */
259 ppc_mr (p, ppc_r12, ppc_r6); /* keep "arguments" in register */
260 ppc_mr (p, ppc_r0, ppc_r3); /* keep "callme" in register */
262 ppc_stw (p, ppc_r4, stack_size - 12, ppc_r31); /* preserve "retval", sp[+8] */
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); \
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; \
278 inline static guint8*
279 emit_save_parameters (guint8 *p, MonoMethod *method, guint stack_size, guint strings, gint runtime)
281 MonoMethodSignature *sig;
282 guint i, fr, gr, act_strs, stack_par_pos;
287 sig = method->signature;
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);
299 ppc_stw (p, ppc_r3, stack_size - 24 - act_strs, ppc_r31);
306 ppc_mr (p, ppc_r3, ppc_r5);
311 for (i = 0; i < sig->param_count; ++i) {
312 if (sig->params [i]->byref) {
313 SAVE_4_IN_GENERIC_REGISTER;
316 simpletype = sig->params [i]->type;
318 switch (simpletype) {
319 case MONO_TYPE_BOOLEAN:
330 case MONO_TYPE_SZARRAY:
331 case MONO_TYPE_CLASS:
332 case MONO_TYPE_OBJECT:
333 SAVE_4_IN_GENERIC_REGISTER;
335 case MONO_TYPE_VALUETYPE:
336 if (sig->params [i]->data.klass->enumtype) {
337 simpletype = sig->params [i]->data.klass->enum_basetype->type;
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);
348 NOT_IMPLEMENTED ("save value type on stack");
351 case MONO_TYPE_STRING:
352 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || runtime) {
353 SAVE_4_IN_GENERIC_REGISTER;
356 ppc_lwz (p, ppc_r3 + gr, stack_size - 24 - act_strs, ppc_r31);
360 NOT_IMPLEMENTED ("string on stack");
367 ppc_lwz (p, ppc_r3 + gr, i*16, ARG_BASE);
369 ppc_lwz (p, ppc_r3 + gr, i*16 + 4, ARG_BASE);
372 NOT_IMPLEMENTED ("i8 on stack");
377 ppc_lfs (p, ppc_f1 + fr, i*16, ARG_BASE);
380 NOT_IMPLEMENTED ("r4 on stack");
385 ppc_lfd (p, ppc_f1 + fr, i*16, ARG_BASE);
388 NOT_IMPLEMENTED ("r8 on stack");
392 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
399 static inline guint8 *
400 alloc_code_memory (guint code_size)
405 p = g_malloc (code_size + PAGESIZE - 1);
407 /* Align to a multiple of PAGESIZE, assumed to be a power of two */
408 p = (char *)(((int) p + PAGESIZE-1) & ~(PAGESIZE-1));
410 p = g_malloc (code_size);
412 DEBUG (printf (" align: %p (%d)\n", p, (guint)p % 4));
417 /* static MonoString*
418 mono_string_new_wrapper (const char *text)
420 return text ? mono_string_new (mono_domain_get (), text) : NULL;
423 static inline guint8 *
424 emit_call_and_store_retval (guint8 *p, MonoMethod *method, guint stack_size, guint strings, gint runtime)
426 MonoMethodSignature *sig = method->signature;
430 ppc_mtlr (p, strings ? ppc_r29 : ppc_r0);
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" */
440 simpletype = sig->ret->type;
442 switch (simpletype) {
443 case MONO_TYPE_BOOLEAN:
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" */
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" */
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" */
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);
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" */
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" */
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" */
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" */
491 case MONO_TYPE_VALUETYPE:
492 if (sig->ret->data.klass->enumtype) {
493 simpletype = sig->ret->data.klass->enum_basetype->type;
496 NOT_IMPLEMENTED ("retval valuetype");
501 g_error ("Can't handle as return value 0x%x", sig->ret->type);
508 static inline guint8 *
509 emit_epilog (guint8 *p, MonoMethod *method, guint stack_size, guint strings, gboolean runtime)
512 MonoMethodSignature *sig = method->signature;
515 /* free allocated memory */
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);
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);
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 */
549 mono_create_trampoline (MonoMethod *method, int runtime)
551 guint8 *p, *code_buffer;
552 guint stack_size, code_size, strings;
554 DEBUG (printf ("\nPInvoke [start emiting] %s\n", method->name));
555 calculate_sizes (method, &stack_size, &code_size, &strings, runtime);
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);
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);
572 if (mprotect (code_buffer, 1024, PROT_READ | PROT_WRITE | PROT_EXEC)) {
573 g_error ("Cannot mprotect trampoline\n");
577 DEBUG (printf ("emited code size: %d\n", p - code_buffer));
578 flush_icache (code_buffer, p - code_buffer);
580 DEBUG (printf ("PInvoke [end emiting]\n"));
582 return (MonoPIFunc) code_buffer;
583 /* return fake_func; */
587 #define MINV_POS 8 /* MonoInvocation structure offset on stack */
588 #define STACK_POS (MINV_POS - sizeof (stackval) * sig->param_count)
590 #define TYPE_OFFSET (G_STRUCT_OFFSET (stackval, type))
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.
603 mono_create_method_pointer (MonoMethod *method)
605 MonoMethodSignature *sig;
607 guint8 *p, *code_buffer;
608 guint i, code_size, stack_size, stackval_arg_pos, local_pos, local_start, reg_param, stack_param;
615 sig = method->signature;
617 p = code_buffer = g_malloc (code_size);
619 DEBUG (printf ("\nDelegate [start emiting] %s\n", method->name));
622 ppc_stwu (p, ppc_r1, -stack_size, ppc_r1); /* sp <--- sp - stack_size, sp[0] <---- sp save sp, alloc stack */
623 ppc_mflr (p, ppc_r0); /* r0 <--- LR */
624 ppc_stw (p, ppc_r31, stack_size - 4, ppc_r1); /* sp[+4] <--- r31 save r31 */
625 ppc_stw (p, ppc_r0, stack_size + 4, ppc_r1); /* sp[-4] <--- LR save return address for "callme" */
626 ppc_mr (p, ppc_r31, ppc_r1); /* r31 <--- sp */
628 /* let's fill MonoInvocation */
629 /* first zero some fields */
630 ppc_li (p, ppc_r0, 0);
631 ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex)), ppc_r31);
632 ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex_handler)), ppc_r31);
633 ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, child)), ppc_r31);
634 ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, parent)), ppc_r31);
636 /* set method pointer */
637 ppc_lis (p, ppc_r0, (guint32) method >> 16);
638 ppc_ori (p, ppc_r0, ppc_r0, (guint32) method & 0xffff);
639 ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, method)), ppc_r31);
641 local_start = local_pos = MINV_POS + sizeof (MonoInvocation) + (sig->param_count + 1) * sizeof (stackval);
644 ppc_stw (p, ppc_r3, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj)), ppc_r31);
647 ppc_stw (p, ppc_r3, local_pos, ppc_r31);
651 ppc_stw (p, ppc_r4, local_pos, ppc_r31); local_pos += 4;
652 ppc_stw (p, ppc_r5, local_pos, ppc_r31); local_pos += 4;
654 /* set MonoInvocation::stack_args */
655 stackval_arg_pos = MINV_POS + sizeof (MonoInvocation);
656 ppc_addi (p, ppc_r0, ppc_r31, stackval_arg_pos);
657 ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, stack_args)), ppc_r31);
659 /* add stackval arguments */
660 for (i = 0; i < sig->param_count; ++i) {
661 #define CALL_STACKVAL_FROM_DATA \
662 ppc_lis (p, ppc_r0, (guint32) stackval_from_data >> 16); \
663 ppc_ori (p, ppc_r0, ppc_r0, (guint32) stackval_from_data & 0xffff); \
664 ppc_mtlr (p, ppc_r0); \
666 #define CALL_SIZE_4 \
667 if (reg_param < 3 - (sig->hasthis ? 1 : 0)) { \
668 ppc_addi (p, ppc_r5, ppc_r31, local_start + (reg_param - (sig->hasthis ? 1 : 0))*4); \
670 } else if (reg_param < 8) { \
671 ppc_stw (p, ppc_r3 + reg_param, local_pos, ppc_r31); \
672 ppc_addi (p, ppc_r5, ppc_r31, local_pos); \
675 ppc_addi (p, ppc_r5, stack_size + 8 + stack_param, ppc_r31); \
678 ppc_lis (p, ppc_r3, (guint32) sig->params [i] >> 16); \
679 ppc_addi (p, ppc_r4, ppc_r31, stackval_arg_pos); \
680 stackval_arg_pos ++; \
681 ppc_ori (p, ppc_r3, ppc_r3, (guint32) sig->params [i] & 0xffff); \
683 CALL_STACKVAL_FROM_DATA
685 if (sig->params [i]->byref) {
689 simpletype = sig->params [i]->type;
691 switch (simpletype) {
692 case MONO_TYPE_BOOLEAN:
703 case MONO_TYPE_SZARRAY:
704 case MONO_TYPE_CLASS:
705 case MONO_TYPE_OBJECT:
706 case MONO_TYPE_STRING:
709 case MONO_TYPE_VALUETYPE:
710 NOT_IMPLEMENTED ("value type");
713 NOT_IMPLEMENTED ("i8");
716 NOT_IMPLEMENTED ("r4");
719 NOT_IMPLEMENTED ("r8");
722 g_error ("Can't delegate 0x%x type", sig->params [i]->type);
726 /* return value storage */
727 if (sig->param_count) {
728 ppc_addi (p, ppc_r0, ppc_r31, stackval_arg_pos);
730 ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, retval)), ppc_r31);
732 /* call ves_exec_method */
733 ppc_lis (p, ppc_r0, (guint32) ves_exec_method >> 16);
734 ppc_addi (p, ppc_r3, ppc_r31, MINV_POS);
735 ppc_ori (p, ppc_r0, ppc_r0, (guint32) ves_exec_method & 0xffff);
736 ppc_mtlr (p, ppc_r0);
739 /* move retval from stackval to proper place (r3/r4/...) */
740 if (sig->ret->byref) {
741 DEBUG (printf ("ret by ref\n"));
742 ppc_lwz (p, ppc_r3, stackval_arg_pos, ppc_r31);
744 switch (sig->ret->type) {
747 case MONO_TYPE_BOOLEAN:
750 ppc_lbz (p, ppc_r3, stackval_arg_pos, ppc_r31);
754 ppc_lhz (p, ppc_r3, stackval_arg_pos, ppc_r31);
760 case MONO_TYPE_OBJECT:
761 case MONO_TYPE_STRING:
762 case MONO_TYPE_CLASS:
763 ppc_lwz (p, ppc_r3, stackval_arg_pos, ppc_r31);
766 ppc_lwz (p, ppc_r3, stackval_arg_pos, ppc_r31);
767 ppc_lwz (p, ppc_r4, stackval_arg_pos + 4, ppc_r31);
770 ppc_lfs (p, ppc_f1, stackval_arg_pos, ppc_r31);
773 ppc_lfd (p, ppc_f1, stackval_arg_pos, ppc_r31);
776 g_error ("Type 0x%x not handled yet in thunk creation", sig->ret->type);
782 ppc_lwz (p, ppc_r11, 0, ppc_r1); /* r11 <--- sp[0] load backchain from caller's function */
783 ppc_lwz (p, ppc_r0, 4, ppc_r11); /* r0 <--- r11[4] load return address */
784 ppc_mtlr (p, ppc_r0); /* LR <--- r0 set return address */
785 ppc_lwz (p, ppc_r31, -4, ppc_r11); /* r31 <--- r11[-4] restore r31 */
786 ppc_mr (p, ppc_r1, ppc_r11); /* sp <--- r11 restore stack */
787 ppc_blr (p); /* return */
789 DEBUG (printf ("emited code size: %d\n", p - code_buffer));
790 flush_icache (code_buffer, p - code_buffer);
792 DEBUG (printf ("Delegate [end emiting]\n"));
794 ji = g_new0 (MonoJitInfo, 1);
796 ji->code_size = p - code_buffer;
797 ji->code_start = code_buffer;
799 mono_jit_info_table_add (mono_root_domain, ji);
801 return ji->code_start;