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 (MonoMethodSignature *sig, guint *stack_size, guint *code_size, gboolean string_ctor)
101 *stack_size = MINIMAL_STACK_SIZE*4;
102 *code_size = (PROLOG_INS + CALL_INS + EPILOG_INS)*4;
105 add_general (&gr, stack_size, code_size, TRUE);
108 for (i = 0; i < sig->param_count; ++i) {
109 if (sig->params [i]->byref) {
110 add_general (&gr, stack_size, code_size, TRUE);
113 simpletype = sig->params [i]->type;
115 switch (simpletype) {
116 case MONO_TYPE_BOOLEAN:
127 case MONO_TYPE_CLASS:
128 case MONO_TYPE_OBJECT:
129 case MONO_TYPE_STRING:
130 add_general (&gr, stack_size, code_size, TRUE);
132 case MONO_TYPE_SZARRAY:
133 add_general (&gr, stack_size, code_size, TRUE);
136 case MONO_TYPE_VALUETYPE:
137 if (sig->params [i]->data.klass->enumtype) {
138 simpletype = sig->params [i]->data.klass->enum_basetype->type;
141 if (mono_class_value_size (sig->params [i]->data.klass, NULL) != 4)
142 g_error ("can only marshal enums, not generic structures (size: %d)",
143 mono_class_value_size (sig->params [i]->data.klass, NULL));
144 add_general (&gr, stack_size, code_size, TRUE);
148 add_general (&gr, stack_size, code_size, FALSE);
156 NOT_IMPLEMENTED ("R8 arg");
160 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
164 if (sig->ret->byref || string_ctor) {
167 simpletype = sig->ret->type;
169 switch (simpletype) {
170 case MONO_TYPE_BOOLEAN:
180 case MONO_TYPE_CLASS:
181 case MONO_TYPE_OBJECT:
184 case MONO_TYPE_SZARRAY:
185 case MONO_TYPE_ARRAY:
186 case MONO_TYPE_STRING:
192 case MONO_TYPE_VALUETYPE:
193 if (sig->ret->data.klass->enumtype) {
194 simpletype = sig->ret->data.klass->enum_basetype->type;
197 NOT_IMPLEMENTED ("valuetype");
202 g_error ("Can't handle as return value 0x%x", sig->ret->type);
206 /* align stack size to 16 */
207 DEBUG (printf (" stack size: %d (%d)\n code size: %d\n", (*stack_size + 15) & ~15, *stack_size, *code_size));
208 *stack_size = (*stack_size + 15) & ~15;
212 static inline guint8 *
213 emit_prolog (guint8 *p, MonoMethodSignature *sig, guint stack_size)
215 /* function prolog */
216 ppc_stwu (p, ppc_r1, -stack_size, ppc_r1); /* sp <--- sp - stack_size, sp[0] <---- sp save sp, alloc stack */
217 ppc_mflr (p, ppc_r0); /* r0 <--- LR */
218 ppc_stw (p, ppc_r31, stack_size - 4, ppc_r1); /* sp[+4] <--- r31 save r31 */
219 ppc_stw (p, ppc_r0, stack_size + 4, ppc_r1); /* sp[-4] <--- LR save return address for "callme" */
220 ppc_mr (p, ppc_r31, ppc_r1); /* r31 <--- sp */
222 ppc_mr (p, ppc_r12, ppc_r6); /* keep "arguments" in register */
223 ppc_mr (p, ppc_r0, ppc_r3); /* keep "callme" in register */
225 ppc_stw (p, ppc_r4, stack_size - 12, ppc_r31); /* preserve "retval", sp[+8] */
230 #define ARG_BASE ppc_r12
231 #define SAVE_4_IN_GENERIC_REGISTER \
232 if (gr < GENERAL_REGS) { \
233 ppc_lwz (p, ppc_r3 + gr, i*16, ARG_BASE); \
236 ppc_lwz (p, ppc_r11, i*16, ARG_BASE); \
237 ppc_stw (p, ppc_r11, stack_par_pos, ppc_r1); \
238 stack_par_pos += 4; \
241 inline static guint8*
242 emit_save_parameters (guint8 *p, MonoMethodSignature *sig, guint stack_size)
244 guint i, fr, gr, act_strs, stack_par_pos;
252 ppc_mr (p, ppc_r3, ppc_r5);
257 for (i = 0; i < sig->param_count; ++i) {
258 if (sig->params [i]->byref) {
259 SAVE_4_IN_GENERIC_REGISTER;
262 simpletype = sig->params [i]->type;
264 switch (simpletype) {
265 case MONO_TYPE_BOOLEAN:
276 case MONO_TYPE_CLASS:
277 case MONO_TYPE_OBJECT:
278 case MONO_TYPE_STRING:
279 case MONO_TYPE_SZARRAY:
280 SAVE_4_IN_GENERIC_REGISTER;
282 /* g_warning ("untested marshaling\n");
283 if (gr < GENERAL_REGS) {
284 ppc_lwz (p, ppc_r3 + gr, i*16, ARG_BASE);
285 ppc_lwz (p, ppc_r3 + gr, G_STRUCT_OFFSET (MonoArray, vector), ppc_r3 + gr);
288 NOT_IMPLEMENTED ("save marshalled SZARRAY on stack");
291 case MONO_TYPE_VALUETYPE:
292 if (sig->params [i]->data.klass->enumtype) {
293 simpletype = sig->params [i]->data.klass->enum_basetype->type;
296 if (mono_class_value_size (sig->params [i]->data.klass, NULL) != 4)
297 g_error ("can only marshal enums, not generic structures (size: %d)",
298 mono_class_value_size (sig->params [i]->data.klass, NULL));
299 if (gr < GENERAL_REGS) {
300 ppc_lwz (p, ppc_r3 + gr, i*16, ARG_BASE);
301 ppc_lwz (p, ppc_r3 + gr, 0, ppc_r3 + gr);
304 NOT_IMPLEMENTED ("save value type on stack");
311 ppc_lwz (p, ppc_r3 + gr, i*16, ARG_BASE);
313 ppc_lwz (p, ppc_r3 + gr, i*16 + 4, ARG_BASE);
316 NOT_IMPLEMENTED ("i8 on stack");
321 ppc_lfs (p, ppc_f1 + fr, i*16, ARG_BASE);
324 NOT_IMPLEMENTED ("r4 on stack");
329 ppc_lfd (p, ppc_f1 + fr, i*16, ARG_BASE);
332 NOT_IMPLEMENTED ("r8 on stack");
336 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
343 static inline guint8 *
344 alloc_code_memory (guint code_size)
349 p = g_malloc (code_size + PAGESIZE - 1);
351 /* Align to a multiple of PAGESIZE, assumed to be a power of two */
352 p = (char *)(((int) p + PAGESIZE-1) & ~(PAGESIZE-1));
354 p = g_malloc (code_size);
356 DEBUG (printf (" align: %p (%d)\n", p, (guint)p % 4));
361 /* static MonoString*
362 mono_string_new_wrapper (const char *text)
364 return text ? mono_string_new (mono_domain_get (), text) : NULL;
367 static inline guint8 *
368 emit_call_and_store_retval (guint8 *p, MonoMethodSignature *sig, guint stack_size, gboolean string_ctor)
373 ppc_mtlr (p, ppc_r0);
376 /* get return value */
377 if (sig->ret->byref || string_ctor) {
378 ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */
379 ppc_stw (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
381 simpletype = sig->ret->type;
383 switch (simpletype) {
384 case MONO_TYPE_BOOLEAN:
387 ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */
388 ppc_stb (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
393 ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */
394 ppc_sth (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
400 case MONO_TYPE_CLASS:
401 case MONO_TYPE_OBJECT:
402 case MONO_TYPE_SZARRAY:
403 case MONO_TYPE_ARRAY:
404 case MONO_TYPE_STRING:
405 ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */
406 ppc_stw (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
409 ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */
410 ppc_stfs (p, ppc_f1, 0, ppc_r9); /* save return value (f1) to "retval" */
413 ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */
414 ppc_stfd (p, ppc_f1, 0, ppc_r9); /* save return value (f1) to "retval" */
417 ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */
418 ppc_stw (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
419 ppc_stw (p, ppc_r4, 4, ppc_r9); /* save return value (r3) to "retval" */
421 case MONO_TYPE_VALUETYPE:
422 if (sig->ret->data.klass->enumtype) {
423 simpletype = sig->ret->data.klass->enum_basetype->type;
426 NOT_IMPLEMENTED ("retval valuetype");
431 g_error ("Can't handle as return value 0x%x", sig->ret->type);
438 static inline guint8 *
439 emit_epilog (guint8 *p, MonoMethodSignature *sig, guint stack_size)
441 /* function epilog */
442 ppc_lwz (p, ppc_r11, 0, ppc_r1); /* r11 <--- sp[0] load backchain from caller's function */
443 ppc_lwz (p, ppc_r0, 4, ppc_r11); /* r0 <--- r11[4] load return address */
444 ppc_mtlr (p, ppc_r0); /* LR <--- r0 set return address */
445 ppc_lwz (p, ppc_r31, -4, ppc_r11); /* r31 <--- r11[-4] restore r31 */
446 ppc_mr (p, ppc_r1, ppc_r11); /* sp <--- r11 restore stack */
447 ppc_blr (p); /* return */
453 mono_create_trampoline (MonoMethodSignature *sig, gboolean string_ctor)
455 guint8 *p, *code_buffer;
456 guint stack_size, code_size;
458 DEBUG (printf ("\nPInvoke [start emiting]\n"));
459 calculate_sizes (sig, &stack_size, &code_size, string_ctor);
461 p = code_buffer = alloc_code_memory (code_size);
462 p = emit_prolog (p, sig, stack_size);
463 p = emit_save_parameters (p, sig, stack_size);
464 p = emit_call_and_store_retval (p, sig, stack_size, string_ctor);
465 p = emit_epilog (p, sig, stack_size);
469 printf (".text\n.align 4\n.globl main\n.type main,@function\nmain:\n");
470 for (cp = code_buffer; cp < p; cp++) {
471 printf (".byte 0x%x\n", *cp);
476 if (mprotect (code_buffer, 1024, PROT_READ | PROT_WRITE | PROT_EXEC)) {
477 g_error ("Cannot mprotect trampoline\n");
481 DEBUG (printf ("emited code size: %d\n", p - code_buffer));
482 flush_icache (code_buffer, p - code_buffer);
484 DEBUG (printf ("PInvoke [end emiting]\n"));
486 return (MonoPIFunc) code_buffer;
487 /* return fake_func; */
491 #define MINV_POS 8 /* MonoInvocation structure offset on stack */
492 #define STACK_POS (MINV_POS - sizeof (stackval) * sig->param_count)
494 #define TYPE_OFFSET (G_STRUCT_OFFSET (stackval, type))
497 * Returns a pointer to a native function that can be used to
498 * call the specified method.
499 * The function created will receive the arguments according
500 * to the call convention specified in the method.
501 * This function works by creating a MonoInvocation structure,
502 * filling the fields in and calling ves_exec_method on it.
503 * Still need to figure out how to handle the exception stuff
504 * across the managed/unmanaged boundary.
507 mono_create_method_pointer (MonoMethod *method)
509 MonoMethodSignature *sig;
511 guint8 *p, *code_buffer;
512 guint i, code_size, stack_size, stackval_arg_pos, local_pos, local_start, reg_param, stack_param;
519 sig = method->signature;
521 p = code_buffer = g_malloc (code_size);
523 DEBUG (printf ("\nDelegate [start emiting] %s\n", method->name));
526 ppc_stwu (p, ppc_r1, -stack_size, ppc_r1); /* sp <--- sp - stack_size, sp[0] <---- sp save sp, alloc stack */
527 ppc_mflr (p, ppc_r0); /* r0 <--- LR */
528 ppc_stw (p, ppc_r31, stack_size - 4, ppc_r1); /* sp[+4] <--- r31 save r31 */
529 ppc_stw (p, ppc_r0, stack_size + 4, ppc_r1); /* sp[-4] <--- LR save return address for "callme" */
530 ppc_mr (p, ppc_r31, ppc_r1); /* r31 <--- sp */
532 /* let's fill MonoInvocation */
533 /* first zero some fields */
534 ppc_li (p, ppc_r0, 0);
535 ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex)), ppc_r31);
536 ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex_handler)), ppc_r31);
537 ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, child)), ppc_r31);
538 ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, parent)), ppc_r31);
540 /* set method pointer */
541 ppc_lis (p, ppc_r0, (guint32) method >> 16);
542 ppc_ori (p, ppc_r0, ppc_r0, (guint32) method & 0xffff);
543 ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, method)), ppc_r31);
545 local_start = local_pos = MINV_POS + sizeof (MonoInvocation) + (sig->param_count + 1) * sizeof (stackval);
548 ppc_stw (p, ppc_r3, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj)), ppc_r31);
551 ppc_stw (p, ppc_r3, local_pos, ppc_r31);
555 ppc_stw (p, ppc_r4, local_pos, ppc_r31); local_pos += 4;
556 ppc_stw (p, ppc_r5, local_pos, ppc_r31); local_pos += 4;
558 /* set MonoInvocation::stack_args */
559 stackval_arg_pos = MINV_POS + sizeof (MonoInvocation);
560 ppc_addi (p, ppc_r0, ppc_r31, stackval_arg_pos);
561 ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, stack_args)), ppc_r31);
563 /* add stackval arguments */
564 for (i = 0; i < sig->param_count; ++i) {
565 #define CALL_STACKVAL_FROM_DATA \
566 ppc_lis (p, ppc_r0, (guint32) stackval_from_data >> 16); \
567 ppc_ori (p, ppc_r0, ppc_r0, (guint32) stackval_from_data & 0xffff); \
568 ppc_mtlr (p, ppc_r0); \
570 #define CALL_SIZE_4 \
571 if (reg_param < 3 - (sig->hasthis ? 1 : 0)) { \
572 ppc_addi (p, ppc_r5, ppc_r31, local_start + (reg_param - (sig->hasthis ? 1 : 0))*4); \
574 } else if (reg_param < 8) { \
575 ppc_stw (p, ppc_r3 + reg_param, local_pos, ppc_r31); \
576 ppc_addi (p, ppc_r5, ppc_r31, local_pos); \
579 ppc_addi (p, ppc_r5, stack_size + 8 + stack_param, ppc_r31); \
582 ppc_lis (p, ppc_r3, (guint32) sig->params [i] >> 16); \
583 ppc_addi (p, ppc_r4, ppc_r31, stackval_arg_pos); \
584 stackval_arg_pos ++; \
585 ppc_ori (p, ppc_r3, ppc_r3, (guint32) sig->params [i] & 0xffff); \
587 CALL_STACKVAL_FROM_DATA
589 if (sig->params [i]->byref) {
593 simpletype = sig->params [i]->type;
595 switch (simpletype) {
596 case MONO_TYPE_BOOLEAN:
607 case MONO_TYPE_SZARRAY:
608 case MONO_TYPE_CLASS:
609 case MONO_TYPE_OBJECT:
610 case MONO_TYPE_STRING:
613 case MONO_TYPE_VALUETYPE:
614 NOT_IMPLEMENTED ("value type");
617 NOT_IMPLEMENTED ("i8");
620 NOT_IMPLEMENTED ("r4");
623 NOT_IMPLEMENTED ("r8");
626 g_error ("Can't delegate 0x%x type", sig->params [i]->type);
630 /* return value storage */
631 if (sig->param_count) {
632 ppc_addi (p, ppc_r0, ppc_r31, stackval_arg_pos);
634 ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, retval)), ppc_r31);
636 /* call ves_exec_method */
637 ppc_lis (p, ppc_r0, (guint32) ves_exec_method >> 16);
638 ppc_addi (p, ppc_r3, ppc_r31, MINV_POS);
639 ppc_ori (p, ppc_r0, ppc_r0, (guint32) ves_exec_method & 0xffff);
640 ppc_mtlr (p, ppc_r0);
643 /* move retval from stackval to proper place (r3/r4/...) */
644 if (sig->ret->byref) {
645 DEBUG (printf ("ret by ref\n"));
646 ppc_lwz (p, ppc_r3, stackval_arg_pos, ppc_r31);
648 switch (sig->ret->type) {
651 case MONO_TYPE_BOOLEAN:
654 ppc_lbz (p, ppc_r3, stackval_arg_pos, ppc_r31);
658 ppc_lhz (p, ppc_r3, stackval_arg_pos, ppc_r31);
664 case MONO_TYPE_OBJECT:
665 case MONO_TYPE_STRING:
666 case MONO_TYPE_CLASS:
667 ppc_lwz (p, ppc_r3, stackval_arg_pos, ppc_r31);
670 ppc_lwz (p, ppc_r3, stackval_arg_pos, ppc_r31);
671 ppc_lwz (p, ppc_r4, stackval_arg_pos + 4, ppc_r31);
674 ppc_lfs (p, ppc_f1, stackval_arg_pos, ppc_r31);
677 ppc_lfd (p, ppc_f1, stackval_arg_pos, ppc_r31);
680 g_error ("Type 0x%x not handled yet in thunk creation", sig->ret->type);
686 ppc_lwz (p, ppc_r11, 0, ppc_r1); /* r11 <--- sp[0] load backchain from caller's function */
687 ppc_lwz (p, ppc_r0, 4, ppc_r11); /* r0 <--- r11[4] load return address */
688 ppc_mtlr (p, ppc_r0); /* LR <--- r0 set return address */
689 ppc_lwz (p, ppc_r31, -4, ppc_r11); /* r31 <--- r11[-4] restore r31 */
690 ppc_mr (p, ppc_r1, ppc_r11); /* sp <--- r11 restore stack */
691 ppc_blr (p); /* return */
693 DEBUG (printf ("emited code size: %d\n", p - code_buffer));
694 flush_icache (code_buffer, p - code_buffer);
696 DEBUG (printf ("Delegate [end emiting]\n"));
698 ji = g_new0 (MonoJitInfo, 1);
700 ji->code_size = p - code_buffer;
701 ji->code_start = code_buffer;
703 mono_jit_info_table_add (mono_root_domain, ji);
705 return ji->code_start;