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 */
25 fake_func (gpointer (*callme)(gpointer), stackval *retval, void *this_obj, stackval *arguments)
27 guint32 i = 0xc002becd;
29 callme = (gpointer) 0x100fabcd;
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);
34 return (gpointer) (*callme) (((MonoType *)arguments [0]. data.p)->data.klass);
37 #define MIN_CACHE_LINE 8
40 flush_icache (guint8 *code, guint size)
46 for (i = 0; i < size; i += MIN_CACHE_LINE, p += MIN_CACHE_LINE) {
47 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
51 for (i = 0; i < size; i += MIN_CACHE_LINE, p += MIN_CACHE_LINE) {
52 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
58 #define NOT_IMPLEMENTED(x) \
59 g_error ("FIXME: %s is not yet implemented. (trampoline)", x);
64 #define MINIMAL_STACK_SIZE 5
66 #define GENERAL_REGS 8
69 add_general (guint *gr, guint *stack_size, guint *code_size, gboolean simple)
72 if (*gr >= GENERAL_REGS) {
74 *code_size += 8; /* load from stack, save on stack */
76 *code_size += 4; /* load from stack */
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 */
83 *code_size += 16; /* 2x load from stack */
93 calculate_sizes (MonoMethod *method, guint *stack_size, guint *code_size, guint *strings, gint runtime)
95 MonoMethodSignature *sig;
100 *stack_size = MINIMAL_STACK_SIZE*4;
101 *code_size = (PROLOG_INS + CALL_INS + EPILOG_INS)*4;
104 sig = method->signature;
106 add_general (&gr, stack_size, code_size, TRUE);
109 for (i = 0; i < sig->param_count; ++i) {
110 if (sig->params [i]->byref) {
111 add_general (&gr, stack_size, code_size, TRUE);
114 simpletype = sig->params [i]->type;
116 switch (simpletype) {
117 case MONO_TYPE_BOOLEAN:
128 case MONO_TYPE_SZARRAY:
129 case MONO_TYPE_CLASS:
130 case MONO_TYPE_OBJECT:
131 add_general (&gr, stack_size, code_size, TRUE);
133 case MONO_TYPE_VALUETYPE:
134 if (sig->params [i]->data.klass->enumtype) {
135 simpletype = sig->params [i]->data.klass->enum_basetype->type;
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);
144 case MONO_TYPE_STRING:
145 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || runtime) {
146 add_general (&gr, stack_size, code_size, TRUE);
154 add_general (&gr, stack_size, code_size, FALSE);
162 NOT_IMPLEMENTED ("R8 arg");
166 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
170 if (sig->ret->byref ||
171 (method->klass == mono_defaults.string_class &&
172 *method->name == '.' && !strcmp (method->name, ".ctor"))) {
175 simpletype = sig->ret->type;
177 switch (simpletype) {
178 case MONO_TYPE_BOOLEAN:
188 case MONO_TYPE_CLASS:
189 case MONO_TYPE_OBJECT:
192 case MONO_TYPE_SZARRAY:
193 case MONO_TYPE_ARRAY:
196 case MONO_TYPE_STRING:
198 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && !runtime) {
205 case MONO_TYPE_VALUETYPE:
206 if (sig->ret->data.klass->enumtype) {
207 simpletype = sig->ret->data.klass->enum_basetype->type;
210 NOT_IMPLEMENTED ("valuetype");
215 g_error ("Can't handle as return value 0x%x", sig->ret->type);
220 /* space to keep parameters and prepared strings */
228 /* align stack size to 16 */
229 printf (" stack size: %d (%d)\n code size: %d\n", (*stack_size + 15) & ~15, *stack_size, *code_size);
230 *stack_size = (*stack_size + 15) & ~15;
234 static inline guint8 *
235 emit_prolog (guint8 *p, MonoMethod *method, guint stack_size, guint strings)
237 /* function prolog */
238 ppc_stwu (p, ppc_r1, -stack_size, ppc_r1); /* sp <--- sp - stack_size, sp[0] <---- sp save sp, alloc stack */
239 ppc_mflr (p, ppc_r0); /* r0 <--- LR */
240 ppc_stw (p, ppc_r31, stack_size - 4, ppc_r1); /* sp[+4] <--- r31 save r31 */
241 ppc_stw (p, ppc_r0, stack_size + 4, ppc_r1); /* sp[-4] <--- LR save return address for "callme" */
242 ppc_mr (p, ppc_r31, ppc_r1); /* r31 <--- sp */
244 /* handle our parameters */
246 ppc_stw (p, ppc_r30, stack_size - 16, ppc_r1);
247 ppc_stw (p, ppc_r29, stack_size - 12, ppc_r1);
248 if (method->signature->hasthis) {
249 ppc_stw (p, ppc_r28, 24, ppc_r1);
251 ppc_mr (p, ppc_r30, ppc_r6); /* args */
252 ppc_mr (p, ppc_r29, ppc_r3); /* callme */
253 if (method->signature->hasthis) {
254 ppc_mr (p, ppc_r28, ppc_r5); /* this */
257 ppc_mr (p, ppc_r12, ppc_r6); /* keep "arguments" in register */
258 ppc_mr (p, ppc_r0, ppc_r3); /* keep "callme" in register */
260 ppc_stw (p, ppc_r4, stack_size - 12, ppc_r31); /* preserve "retval", sp[+8] */
265 #define ARG_BASE strings ? ppc_r30 : ppc_r12
266 #define SAVE_4_IN_GENERIC_REGISTER \
267 if (gr < GENERAL_REGS) { \
268 ppc_lwz (p, ppc_r3 + gr, i*16, ARG_BASE); \
271 ppc_lwz (p, ppc_r11, i*16, ARG_BASE); \
272 ppc_stw (p, ppc_r11, stack_par_pos, ppc_r1); \
273 stack_par_pos += 4; \
276 inline static guint8*
277 emit_save_parameters (guint8 *p, MonoMethod *method, guint stack_size, guint strings, gint runtime)
279 MonoMethodSignature *sig;
280 guint i, fr, gr, act_strs, stack_par_pos;
285 sig = method->signature;
289 for (i = 0; i < sig->param_count; ++i) {
290 if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_STRING
291 && !((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || runtime)) {
292 ppc_lis (p, ppc_r0, (guint32) mono_string_to_utf8 >> 16);
293 ppc_lwz (p, ppc_r3, i*16, ppc_r30);
294 ppc_ori (p, ppc_r0, ppc_r0, (guint32) mono_string_to_utf8 & 0xffff);
295 ppc_mtlr (p, ppc_r0);
297 ppc_stw (p, ppc_r3, stack_size - 24 - act_strs, ppc_r31);
304 ppc_mr (p, ppc_r3, ppc_r5);
309 for (i = 0; i < sig->param_count; ++i) {
310 if (sig->params [i]->byref) {
311 SAVE_4_IN_GENERIC_REGISTER;
314 simpletype = sig->params [i]->type;
316 switch (simpletype) {
317 case MONO_TYPE_BOOLEAN:
328 case MONO_TYPE_SZARRAY:
329 case MONO_TYPE_CLASS:
330 case MONO_TYPE_OBJECT:
331 SAVE_4_IN_GENERIC_REGISTER;
333 case MONO_TYPE_VALUETYPE:
334 if (sig->params [i]->data.klass->enumtype) {
335 simpletype = sig->params [i]->data.klass->enum_basetype->type;
338 if (mono_class_value_size (sig->params [i]->data.klass, NULL) != 4)
339 g_error ("can only marshal enums, not generic structures (size: %d)",
340 mono_class_value_size (sig->params [i]->data.klass, NULL));
341 if (gr < GENERAL_REGS) {
342 ppc_lwz (p, ppc_r3 + gr, i*16, ARG_BASE);
343 ppc_lwz (p, ppc_r3 + gr, 0, ppc_r3 + gr);
346 NOT_IMPLEMENTED ("save value type on stack");
349 case MONO_TYPE_STRING:
350 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || runtime) {
351 SAVE_4_IN_GENERIC_REGISTER;
354 ppc_lwz (p, ppc_r3 + gr, stack_size - 24 - act_strs, ppc_r31);
358 NOT_IMPLEMENTED ("string on stack");
365 g_warning ("check endianess");
366 ppc_lwz (p, ppc_r3 + gr, i*16, ARG_BASE);
368 ppc_lwz (p, ppc_r3 + gr, i*17, ARG_BASE);
371 NOT_IMPLEMENTED ("i8 on stack");
376 ppc_lfs (p, ppc_f1 + fr, i*16, ARG_BASE);
379 NOT_IMPLEMENTED ("r4 on stack");
384 ppc_lfd (p, ppc_f1 + fr, i*16, ARG_BASE);
387 NOT_IMPLEMENTED ("r8 on stack");
391 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
398 static inline guint8 *
399 alloc_code_memory (guint code_size)
404 p = g_malloc (code_size + PAGESIZE - 1);
406 /* Align to a multiple of PAGESIZE, assumed to be a power of two */
407 p = (char *)(((int) p + PAGESIZE-1) & ~(PAGESIZE-1));
409 p = g_malloc (code_size);
411 printf (" align: %p (%d)\n", p, (guint)p % 4);
416 /* static MonoString*
417 mono_string_new_wrapper (const char *text)
419 return text ? mono_string_new (mono_domain_get (), text) : NULL;
422 static inline guint8 *
423 emit_call_and_store_retval (guint8 *p, MonoMethod *method, guint stack_size, guint strings, gint runtime)
425 MonoMethodSignature *sig = method->signature;
429 ppc_mtlr (p, strings ? ppc_r29 : ppc_r0);
432 /* get return value */
433 if (sig->ret->byref ||
434 (method->klass == mono_defaults.string_class &&
435 *method->name == '.' && !strcmp (method->name, ".ctor"))) {
436 ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */
437 ppc_stw (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
439 simpletype = sig->ret->type;
441 switch (simpletype) {
442 case MONO_TYPE_BOOLEAN:
445 ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */
446 ppc_stb (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
451 ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */
452 ppc_sth (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
458 case MONO_TYPE_CLASS:
459 case MONO_TYPE_OBJECT:
460 case MONO_TYPE_SZARRAY:
461 case MONO_TYPE_ARRAY:
462 ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */
463 ppc_stw (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
465 case MONO_TYPE_STRING:
466 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && !runtime) {
467 ppc_lis (p, ppc_r0, (guint32) mono_string_new_wrapper >> 16);
468 ppc_ori (p, ppc_r0, ppc_r0, (guint32) mono_string_new_wrapper & 0xffff);
469 ppc_mtlr (p, ppc_r0);
473 ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */
474 ppc_stw (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
478 ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */
479 ppc_stfs (p, ppc_f1, 0, ppc_r9); /* save return value (f1) to "retval" */
482 ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */
483 ppc_stfd (p, ppc_f1, 0, ppc_r9); /* save return value (f1) to "retval" */
486 g_warning ("check endianess");
487 ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */
488 ppc_stw (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
489 ppc_stw (p, ppc_r4, 4, ppc_r9); /* save return value (r3) to "retval" */
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 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 printf ("emited code size: %d\n", p - code_buffer);
578 flush_icache (code_buffer, p - code_buffer);
580 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;
606 guint8 *p, *code_buffer;
607 guint i, code_size, stack_size, stackval_arg_pos, local_pos, local_start, reg_param, stack_param;
614 sig = method->signature;
616 p = code_buffer = g_malloc (code_size);
618 printf ("\nDelegate [start emiting] %s\n", method->name);
620 /* jump after header which consist of "Mono" + method ptr */
626 *(void **) p = method; p += 4;
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 */
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);
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);
648 local_start = local_pos = MINV_POS + sizeof (MonoInvocation) + (sig->param_count + 1) * sizeof (stackval);
651 ppc_stw (p, ppc_r3, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj)), ppc_r31);
654 ppc_stw (p, ppc_r3, local_pos, ppc_r31);
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;
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);
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); \
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); \
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); \
682 ppc_addi (p, ppc_r5, stack_size + 8 + stack_param, ppc_r31); \
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); \
690 CALL_STACKVAL_FROM_DATA
692 if (sig->params [i]->byref) {
696 simpletype = sig->params [i]->type;
698 switch (simpletype) {
699 case MONO_TYPE_BOOLEAN:
710 case MONO_TYPE_SZARRAY:
711 case MONO_TYPE_CLASS:
712 case MONO_TYPE_OBJECT:
713 case MONO_TYPE_STRING:
716 case MONO_TYPE_VALUETYPE:
717 NOT_IMPLEMENTED ("value type");
720 NOT_IMPLEMENTED ("i8");
723 NOT_IMPLEMENTED ("r4");
726 NOT_IMPLEMENTED ("r8");
729 g_error ("Can't delegate 0x%x type", sig->params [i]->type);
733 /* return value storage */
734 if (sig->param_count) {
735 ppc_addi (p, ppc_r0, ppc_r31, stackval_arg_pos);
737 ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, retval)), ppc_r31);
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);
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);
750 switch (sig->ret->type) {
753 case MONO_TYPE_BOOLEAN:
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);
768 ppc_lwz (p, ppc_r3, stackval_arg_pos, ppc_r31);
769 ppc_lwz (p, ppc_r4, stackval_arg_pos + 1, ppc_r31);
772 ppc_lfs (p, ppc_f1, stackval_arg_pos, ppc_r31);
775 ppc_lfd (p, ppc_f1, stackval_arg_pos, ppc_r31);
778 g_error ("Type 0x%x not handled yet in thunk creation", sig->ret->type);
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 */
791 printf ("emited code size: %d\n", p - code_buffer);
792 flush_icache (code_buffer, p - code_buffer);
794 printf ("Delegate [end emiting]\n");
796 return (MonoPIFunc) code_buffer;
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.
806 mono_method_pointer_get (void *code)
808 unsigned char *c = code;
809 if (c [4] != 'M' || c [5] != 'o' || c [6] != 'n' || c [7] != 'o')
811 return *(MonoMethod**)(c + 8);