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) {
173 simpletype = sig->ret->type;
175 switch (simpletype) {
176 case MONO_TYPE_BOOLEAN:
186 case MONO_TYPE_CLASS:
187 case MONO_TYPE_OBJECT:
190 case MONO_TYPE_SZARRAY:
191 case MONO_TYPE_ARRAY:
194 case MONO_TYPE_STRING:
196 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && !runtime) {
203 case MONO_TYPE_VALUETYPE:
204 if (sig->ret->data.klass->enumtype) {
205 simpletype = sig->ret->data.klass->enum_basetype->type;
208 NOT_IMPLEMENTED ("valuetype");
213 g_error ("Can't handle as return value 0x%x", sig->ret->type);
218 /* space to keep parameters and prepared strings */
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;
232 static inline guint8 *
233 emit_prolog (guint8 *p, MonoMethod *method, guint stack_size, guint strings)
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 */
242 /* handle our parameters */
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);
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 */
255 ppc_mr (p, ppc_r12, ppc_r6); /* keep "arguments" in register */
256 ppc_mr (p, ppc_r0, ppc_r3); /* keep "callme" in register */
258 ppc_stw (p, ppc_r4, stack_size - 12, ppc_r31); /* preserve "retval", sp[+8] */
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); \
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; \
274 inline static guint8*
275 emit_save_parameters (guint8 *p, MonoMethod *method, guint stack_size, guint strings, gint runtime)
277 MonoMethodSignature *sig;
278 guint i, fr, gr, act_strs, stack_par_pos;
283 sig = method->signature;
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);
295 ppc_stw (p, ppc_r3, stack_size - 24 - act_strs, ppc_r31);
302 ppc_mr (p, ppc_r3, ppc_r5);
307 for (i = 0; i < sig->param_count; ++i) {
308 if (sig->params [i]->byref) {
309 SAVE_4_IN_GENERIC_REGISTER;
312 simpletype = sig->params [i]->type;
314 switch (simpletype) {
315 case MONO_TYPE_BOOLEAN:
326 case MONO_TYPE_SZARRAY:
327 case MONO_TYPE_CLASS:
328 case MONO_TYPE_OBJECT:
329 SAVE_4_IN_GENERIC_REGISTER;
331 case MONO_TYPE_VALUETYPE:
332 if (sig->params [i]->data.klass->enumtype) {
333 simpletype = sig->params [i]->data.klass->enum_basetype->type;
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);
344 NOT_IMPLEMENTED ("save value type on stack");
347 case MONO_TYPE_STRING:
348 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || runtime) {
349 SAVE_4_IN_GENERIC_REGISTER;
352 ppc_lwz (p, ppc_r3 + gr, stack_size - 24 - act_strs, ppc_r31);
356 NOT_IMPLEMENTED ("string on stack");
363 g_warning ("check endianess");
364 ppc_lwz (p, ppc_r3 + gr, i*16, ARG_BASE);
366 ppc_lwz (p, ppc_r3 + gr, i*17, ARG_BASE);
369 NOT_IMPLEMENTED ("i8 on stack");
374 ppc_lfs (p, ppc_f1 + fr, i*16, ARG_BASE);
377 NOT_IMPLEMENTED ("r4 on stack");
382 ppc_lfd (p, ppc_f1 + fr, i*16, ARG_BASE);
385 NOT_IMPLEMENTED ("r8 on stack");
389 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
396 static inline guint8 *
397 alloc_code_memory (guint code_size)
402 p = g_malloc (code_size + PAGESIZE - 1);
404 /* Align to a multiple of PAGESIZE, assumed to be a power of two */
405 p = (char *)(((int) p + PAGESIZE-1) & ~(PAGESIZE-1));
407 p = g_malloc (code_size);
409 printf (" align: %p (%d)\n", p, (guint)p % 4);
415 mono_string_new_wrapper (const char *text)
417 return text ? mono_string_new (mono_domain_get (), text) : NULL;
420 static inline guint8 *
421 emit_call_and_store_retval (guint8 *p, MonoMethod *method, guint stack_size, guint strings, gint runtime)
423 MonoMethodSignature *sig = method->signature;
427 ppc_mtlr (p, strings ? ppc_r29 : ppc_r0);
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" */
435 simpletype = sig->ret->type;
437 switch (simpletype) {
438 case MONO_TYPE_BOOLEAN:
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" */
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" */
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" */
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);
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" */
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" */
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" */
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" */
487 case MONO_TYPE_VALUETYPE:
488 if (sig->ret->data.klass->enumtype) {
489 simpletype = sig->ret->data.klass->enum_basetype->type;
492 NOT_IMPLEMENTED ("retval valuetype");
497 g_error ("Can't handle as return value 0x%x", sig->ret->type);
504 static inline guint8 *
505 emit_epilog (guint8 *p, MonoMethod *method, guint stack_size, guint strings, gboolean runtime)
508 MonoMethodSignature *sig = method->signature;
511 /* free allocated memory */
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);
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);
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 */
545 mono_create_trampoline (MonoMethod *method, int runtime)
547 guint8 *p, *code_buffer;
548 guint stack_size, code_size, strings;
550 printf ("\nPInvoke [start emiting] %s\n", method->name);
551 calculate_sizes (method, &stack_size, &code_size, &strings, runtime);
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);
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);
568 if (mprotect (code_buffer, 1024, PROT_READ | PROT_WRITE | PROT_EXEC)) {
569 g_error ("Cannot mprotect trampoline\n");
573 printf ("emited code size: %d\n", p - code_buffer);
574 flush_icache (code_buffer, p - code_buffer);
576 printf ("PInvoke [end emiting]\n");
578 return (MonoPIFunc) code_buffer;
579 /* return fake_func; */
583 #define MINV_POS 8 /* MonoInvocation structure offset on stack */
584 #define STACK_POS (MINV_POS - sizeof (stackval) * sig->param_count)
586 #define TYPE_OFFSET (G_STRUCT_OFFSET (stackval, type))
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.
599 mono_create_method_pointer (MonoMethod *method)
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;
610 sig = method->signature;
612 p = code_buffer = g_malloc (code_size);
614 printf ("\nDelegate [start emiting] %s\n", method->name);
616 /* jump after header which consist of "Mono" + method ptr */
622 *(void **) p = method; p += 4;
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 */
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);
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);
644 local_start = local_pos = MINV_POS + sizeof (MonoInvocation) + (sig->param_count + 1) * sizeof (stackval);
647 ppc_stw (p, ppc_r3, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj)), ppc_r31);
650 ppc_stw (p, ppc_r3, local_pos, ppc_r31);
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;
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);
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); \
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); \
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); \
678 ppc_addi (p, ppc_r5, stack_size + 8 + stack_param, ppc_r31); \
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); \
686 CALL_STACKVAL_FROM_DATA
688 if (sig->params [i]->byref) {
692 simpletype = sig->params [i]->type;
694 switch (simpletype) {
695 case MONO_TYPE_BOOLEAN:
706 case MONO_TYPE_SZARRAY:
707 case MONO_TYPE_CLASS:
708 case MONO_TYPE_OBJECT:
709 case MONO_TYPE_STRING:
712 case MONO_TYPE_VALUETYPE:
713 NOT_IMPLEMENTED ("value type");
716 NOT_IMPLEMENTED ("i8");
719 NOT_IMPLEMENTED ("r4");
722 NOT_IMPLEMENTED ("r8");
725 g_error ("Can't delegate 0x%x type", sig->params [i]->type);
729 /* return value storage */
730 if (sig->param_count) {
731 ppc_addi (p, ppc_r0, ppc_r31, stackval_arg_pos);
733 ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, retval)), ppc_r31);
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);
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);
746 switch (sig->ret->type) {
749 case MONO_TYPE_BOOLEAN:
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);
764 ppc_lwz (p, ppc_r3, stackval_arg_pos, ppc_r31);
765 ppc_lwz (p, ppc_r4, stackval_arg_pos + 1, ppc_r31);
768 ppc_lfs (p, ppc_f1, stackval_arg_pos, ppc_r31);
771 ppc_lfd (p, ppc_f1, stackval_arg_pos, ppc_r31);
774 g_error ("Type 0x%x not handled yet in thunk creation", sig->ret->type);
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 */
787 printf ("emited code size: %d\n", p - code_buffer);
788 flush_icache (code_buffer, p - code_buffer);
790 printf ("Delegate [end emiting]\n");
792 return (MonoPIFunc) code_buffer;
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.
802 mono_method_pointer_get (void *code)
804 unsigned char *c = code;
805 if (c [4] != 'M' || c [5] != 'o' || c [6] != 'n' || c [7] != 'o')
807 return *(MonoMethod**)(c + 8);