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"
17 #include <limits.h> /* for PAGESIZE */
24 fake_func (gdouble (*callme)(), stackval *retval, void *this_obj, stackval *arguments)
26 guint32 i = 0xc002becd;
28 callme = (gpointer) 0x100fabcd;
30 *(gpointer*)retval = (gpointer)(*callme) (arguments [0].data.p, arguments [1].data.p, arguments [2].data.p);
31 *(gdouble*) retval = (gdouble)(*callme) (arguments [0].data.f);
34 #define MIN_CACHE_LINE 8
37 flush_icache (guint8 *code, guint size)
43 for (i = 0; i < size; i += MIN_CACHE_LINE, p += MIN_CACHE_LINE) {
44 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
48 for (i = 0; i < size; i += MIN_CACHE_LINE, p += MIN_CACHE_LINE) {
49 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
55 #define NOT_IMPLEMENTED(x) \
56 g_error ("FIXME: %s is not yet implemented. (trampoline)", x);
61 #define MINIMAL_STACK_SIZE 5
63 #define GENERAL_REGS 8
66 add_general (guint *gr, guint *stack_size, guint *code_size, gboolean simple)
69 if (*gr >= GENERAL_REGS) {
71 *code_size += 8; /* load from stack, save on stack */
73 *code_size += 4; /* load from stack */
76 if (*gr >= GENERAL_REGS - 1) {
77 *stack_size += 8 + (*stack_size % 8);
78 *code_size += 16; /* 2x load from stack, save to stack */
80 *code_size += 16; /* 2x load from stack */
88 calculate_sizes (MonoMethod *method, guint *stack_size, guint *code_size, guint *strings, gint runtime)
90 MonoMethodSignature *sig;
95 *stack_size = MINIMAL_STACK_SIZE*4;
96 *code_size = (PROLOG_INS + CALL_INS + EPILOG_INS)*4;
99 sig = method->signature;
101 add_general (&gr, stack_size, code_size, TRUE);
104 for (i = 0; i < sig->param_count; ++i) {
105 if (sig->params [i]->byref) {
106 add_general (&gr, stack_size, code_size, TRUE);
109 simpletype = sig->params [i]->type;
111 switch (simpletype) {
112 case MONO_TYPE_BOOLEAN:
123 case MONO_TYPE_SZARRAY:
124 case MONO_TYPE_CLASS:
125 case MONO_TYPE_OBJECT:
126 add_general (&gr, stack_size, code_size, TRUE);
128 case MONO_TYPE_VALUETYPE:
129 if (sig->params [i]->data.klass->enumtype) {
130 simpletype = sig->params [i]->data.klass->enum_basetype->type;
133 if (mono_class_value_size (sig->params [i]->data.klass, NULL) != 4)
134 g_error ("can only marshal enums, not generic structures (size: %d)",
135 mono_class_value_size (sig->params [i]->data.klass, NULL));
136 add_general (&gr, stack_size, code_size, TRUE);
139 case MONO_TYPE_STRING:
140 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || runtime) {
141 add_general (&gr, stack_size, code_size, TRUE);
149 add_general (&gr, stack_size, code_size, FALSE);
157 NOT_IMPLEMENTED ("R8 arg");
161 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
165 if (sig->ret->byref) {
168 simpletype = sig->ret->type;
170 switch (simpletype) {
171 case MONO_TYPE_BOOLEAN:
181 case MONO_TYPE_CLASS:
182 case MONO_TYPE_OBJECT:
185 case MONO_TYPE_SZARRAY:
186 case MONO_TYPE_ARRAY:
187 case MONO_TYPE_STRING:
193 case MONO_TYPE_VALUETYPE:
194 if (sig->ret->data.klass->enumtype) {
195 simpletype = sig->ret->data.klass->enum_basetype->type;
198 NOT_IMPLEMENTED ("valuetype");
203 g_error ("Can't handle as return value 0x%x", sig->ret->type);
208 /* space to keep parameters and prepared strings */
216 /* align stack size to 16 */
217 printf (" stack size: %d (%d)\n code size: %d\n", (*stack_size + 15) & ~15, *stack_size, *code_size);
218 *stack_size = (*stack_size + 15) & ~15;
222 static inline guint8 *
223 emit_prolog (guint8 *p, MonoMethod *method, guint stack_size, guint strings)
225 /* function prolog */
226 ppc_stwu (p, ppc_r1, -stack_size, ppc_r1); /* sp <--- sp - stack_size, sp[0] <---- sp save sp, alloc stack */
227 ppc_mflr (p, ppc_r0); /* r0 <--- LR */
228 ppc_stw (p, ppc_r31, stack_size - 4, ppc_r1); /* sp[+4] <--- r31 save r31 */
229 ppc_stw (p, ppc_r0, stack_size + 4, ppc_r1); /* sp[-4] <--- LR save return address for "callme" */
230 ppc_mr (p, ppc_r31, ppc_r1); /* r31 <--- sp */
232 /* handle our parameters */
234 ppc_stw (p, ppc_r30, stack_size - 16, ppc_r1);
235 ppc_stw (p, ppc_r29, stack_size - 12, ppc_r1);
236 if (method->signature->hasthis) {
237 ppc_stw (p, ppc_r28, 24, ppc_r1);
239 ppc_mr (p, ppc_r30, ppc_r6); /* args */
240 ppc_mr (p, ppc_r29, ppc_r3); /* callme */
241 if (method->signature->hasthis) {
242 ppc_mr (p, ppc_r28, ppc_r5); /* this */
245 ppc_mr (p, ppc_r12, ppc_r6); /* keep "arguments" in register */
246 ppc_mr (p, ppc_r0, ppc_r3); /* keep "callme" in register */
248 ppc_stw (p, ppc_r4, 8, ppc_r31); /* preserve "retval", sp[+8] */
253 #define ARG_BASE strings ? ppc_r30 : ppc_r12
254 #define SAVE_4_IN_GENERIC_REGISTER \
255 if (gr < GENERAL_REGS) { \
256 ppc_lwz (p, ppc_r3 + gr, i*16, ARG_BASE); \
259 NOT_IMPLEMENTED("save on stack"); \
261 #define SAVE_2_IN_GENERIC_REGISTER \
262 if (gr < GENERAL_REGS) { \
263 ppc_lhz (p, ppc_r3 + gr, i*16, ARG_BASE); \
266 NOT_IMPLEMENTED("save on stack"); \
268 #define SAVE_1_IN_GENERIC_REGISTER \
269 if (gr < GENERAL_REGS) { \
270 ppc_lbz (p, ppc_r3 + gr, i*16, ARG_BASE); \
273 NOT_IMPLEMENTED("save on stack"); \
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;
285 sig = method->signature;
288 for (i = 0; i < sig->param_count; ++i) {
289 if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_STRING
290 && !((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || runtime)) {
291 ppc_lis (p, ppc_r0, (guint32) mono_string_to_utf8 >> 16);
292 ppc_lwz (p, ppc_r3, i*16, ppc_r30);
293 ppc_ori (p, ppc_r0, ppc_r0, (guint32) mono_string_to_utf8 & 0xffff);
294 ppc_mtlr (p, ppc_r0);
296 ppc_stw (p, ppc_r3, stack_size - 20 - act_strs, ppc_r31);
303 ppc_mr (p, ppc_r3, ppc_r5);
308 for (i = 0; i < sig->param_count; ++i) {
309 if (sig->params [i]->byref) {
310 SAVE_4_IN_GENERIC_REGISTER;
313 simpletype = sig->params [i]->type;
315 switch (simpletype) {
316 case MONO_TYPE_BOOLEAN:
319 SAVE_1_IN_GENERIC_REGISTER;
324 SAVE_2_IN_GENERIC_REGISTER;
331 case MONO_TYPE_SZARRAY:
332 case MONO_TYPE_CLASS:
333 case MONO_TYPE_OBJECT:
334 SAVE_4_IN_GENERIC_REGISTER;
336 case MONO_TYPE_VALUETYPE:
337 if (sig->params [i]->data.klass->enumtype) {
338 simpletype = sig->params [i]->data.klass->enum_basetype->type;
341 if (mono_class_value_size (sig->params [i]->data.klass, NULL) != 4)
342 g_error ("can only marshal enums, not generic structures (size: %d)",
343 mono_class_value_size (sig->params [i]->data.klass, NULL));
344 if (gr < GENERAL_REGS) {
345 ppc_lwz (p, ppc_r3 + gr, i*16, ARG_BASE);
346 ppc_lwz (p, ppc_r3 + gr, 0, ppc_r3 + gr);
349 NOT_IMPLEMENTED ("save value type on stack");
352 case MONO_TYPE_STRING:
353 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || runtime) {
354 SAVE_4_IN_GENERIC_REGISTER;
357 ppc_lwz (p, ppc_r3 + gr, stack_size - 20 - act_strs, ppc_r31);
361 NOT_IMPLEMENTED ("string on stack");
366 g_warning ("check endianess");
367 ppc_lwz (p, ppc_r3 + gr, i*16, ARG_BASE);
369 ppc_lwz (p, ppc_r3 + gr, i*17, 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 printf (" align: %p (%d)\n", p, (guint)p % 4);
417 static inline guint8 *
418 emit_call_and_store_retval (guint8 *p, MonoMethod *method, guint strings)
420 MonoMethodSignature *sig = method->signature;
424 ppc_mtlr (p, strings ? ppc_r29 : ppc_r0);
427 /* get return value */
428 if (sig->ret->byref) {
429 ppc_lwz (p, ppc_r9, 8, ppc_r31); /* load "retval" address */
430 ppc_stw (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
432 simpletype = sig->ret->type;
434 switch (simpletype) {
435 case MONO_TYPE_BOOLEAN:
438 ppc_lwz (p, ppc_r9, 8, ppc_r31); /* load "retval" address */
439 ppc_stb (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
444 ppc_lwz (p, ppc_r9, 8, ppc_r31); /* load "retval" address */
445 ppc_sth (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
451 case MONO_TYPE_CLASS:
452 case MONO_TYPE_OBJECT:
453 case MONO_TYPE_SZARRAY:
454 case MONO_TYPE_ARRAY:
455 case MONO_TYPE_STRING:
456 ppc_lwz (p, ppc_r9, 8, ppc_r31); /* load "retval" address */
457 ppc_stw (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
460 ppc_lwz (p, ppc_r9, 8, ppc_r31); /* load "retval" address */
461 ppc_stfs (p, ppc_f1, 0, ppc_r9); /* save return value (f1) to "retval" */
464 ppc_lwz (p, ppc_r9, 8, ppc_r31); /* load "retval" address */
465 ppc_stfd (p, ppc_f1, 0, ppc_r9); /* save return value (f1) to "retval" */
468 g_warning ("check endianess");
469 ppc_lwz (p, ppc_r9, 8, ppc_r31); /* load "retval" address */
470 ppc_stw (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
471 ppc_stw (p, ppc_r4, 4, ppc_r9); /* save return value (r3) to "retval" */
473 case MONO_TYPE_VALUETYPE:
474 if (sig->ret->data.klass->enumtype) {
475 simpletype = sig->ret->data.klass->enum_basetype->type;
478 NOT_IMPLEMENTED ("retval valuetype");
483 g_error ("Can't handle as return value 0x%x", sig->ret->type);
490 static inline guint8 *
491 emit_epilog (guint8 *p, MonoMethod *method, guint stack_size, guint strings, gboolean runtime)
494 MonoMethodSignature *sig = method->signature;
497 /* free allocated memory */
499 for (i = 0; i < sig->param_count; ++i) {
500 if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_STRING
501 && !((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || runtime)) {
502 ppc_lis (p, ppc_r0, (guint32) g_free >> 16);
503 ppc_lwz (p, ppc_r3, stack_size - 20 - act_strs, ppc_r31);
504 ppc_ori (p, ppc_r0, ppc_r0, (guint32) g_free & 0xffff);
505 ppc_mtlr (p, ppc_r0);
511 /* restore volatile registers */
512 ppc_lwz (p, ppc_r30, stack_size - 16, ppc_r1);
513 ppc_lwz (p, ppc_r29, stack_size - 12, ppc_r1);
514 if (method->signature->hasthis) {
515 ppc_lwz (p, ppc_r28, 24, ppc_r1);
519 /* function epilog */
520 ppc_lwz (p, ppc_r11, 0, ppc_r1); /* r11 <--- sp[0] load backchain from caller's function */
521 ppc_lwz (p, ppc_r0, 4, ppc_r11); /* r0 <--- r11[4] load return address */
522 ppc_mtlr (p, ppc_r0); /* LR <--- r0 set return address */
523 ppc_lwz (p, ppc_r31, -4, ppc_r11); /* r31 <--- r11[-4] restore r31 */
524 ppc_mr (p, ppc_r1, ppc_r11); /* sp <--- r11 restore stack */
525 ppc_blr (p); /* return */
531 mono_create_trampoline (MonoMethod *method, int runtime)
533 guint8 *p, *code_buffer;
534 guint stack_size, code_size, strings;
536 printf ("\nPInvoke [start emiting] %s\n", method->name);
537 calculate_sizes (method, &stack_size, &code_size, &strings, runtime);
539 p = code_buffer = alloc_code_memory (code_size);
540 p = emit_prolog (p, method, stack_size, strings);
541 p = emit_save_parameters (p, method, stack_size, strings, runtime);
542 p = emit_call_and_store_retval (p, method, strings);
543 p = emit_epilog (p, method, stack_size, strings, runtime);
547 printf (".text\n.align 4\n.globl main\n.type main,@function\nmain:\n");
548 for (cp = code_buffer; cp < p; cp++) {
549 printf (".byte 0x%x\n", *cp);
554 if (mprotect (code_buffer, 1024, PROT_READ | PROT_WRITE | PROT_EXEC)) {
555 g_error ("Cannot mprotect trampoline\n");
559 printf ("emited code size: %d\n", p - code_buffer);
560 flush_icache (code_buffer, p - code_buffer);
562 printf ("PInvoke [end emiting]\n");
564 return (MonoPIFunc) code_buffer;
565 /* return fake_func; */
569 #define MINV_POS (- sizeof (MonoInvocation))
570 #define STACK_POS (MINV_POS - sizeof (stackval) * sig->param_count)
572 #define TYPE_OFFSET (G_STRUCT_OFFSET (stackval, type))
575 * Returns a pointer to a native function that can be used to
576 * call the specified method.
577 * The function created will receive the arguments according
578 * to the call convention specified in the method.
579 * This function works by creating a MonoInvocation structure,
580 * filling the fields in and calling ves_exec_method on it.
581 * Still need to figure out how to handle the exception stuff
582 * across the managed/unmanaged boundary.
585 mono_create_method_pointer (MonoMethod *method)
592 * mono_create_method_pointer () will insert a pointer to the MonoMethod
593 * so that the interp can easily get at the data: this function will retrieve
594 * the method from the code stream.
597 mono_method_pointer_get (void *code)