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, 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, 8, 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 NOT_IMPLEMENTED("save on stack"); \
271 #define SAVE_2_IN_GENERIC_REGISTER \
272 if (gr < GENERAL_REGS) { \
273 ppc_lhz (p, ppc_r3 + gr, i*16, ARG_BASE); \
276 NOT_IMPLEMENTED("save on stack"); \
278 #define SAVE_1_IN_GENERIC_REGISTER \
279 if (gr < GENERAL_REGS) { \
280 ppc_lbz (p, ppc_r3 + gr, i*16, ARG_BASE); \
283 NOT_IMPLEMENTED("save on stack"); \
286 inline static guint8*
287 emit_save_parameters (guint8 *p, MonoMethod *method, guint stack_size, guint strings, gint runtime)
289 MonoMethodSignature *sig;
290 guint i, fr, gr, act_strs;
295 sig = method->signature;
298 for (i = 0; i < sig->param_count; ++i) {
299 if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_STRING
300 && !((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || runtime)) {
301 ppc_lis (p, ppc_r0, (guint32) mono_string_to_utf8 >> 16);
302 ppc_lwz (p, ppc_r3, i*16, ppc_r30);
303 ppc_ori (p, ppc_r0, ppc_r0, (guint32) mono_string_to_utf8 & 0xffff);
304 ppc_mtlr (p, ppc_r0);
306 ppc_stw (p, ppc_r3, stack_size - 20 - act_strs, ppc_r31);
313 ppc_mr (p, ppc_r3, ppc_r5);
318 for (i = 0; i < sig->param_count; ++i) {
319 if (sig->params [i]->byref) {
320 SAVE_4_IN_GENERIC_REGISTER;
323 simpletype = sig->params [i]->type;
325 switch (simpletype) {
326 case MONO_TYPE_BOOLEAN:
329 SAVE_1_IN_GENERIC_REGISTER;
334 SAVE_2_IN_GENERIC_REGISTER;
341 case MONO_TYPE_SZARRAY:
342 case MONO_TYPE_CLASS:
343 case MONO_TYPE_OBJECT:
344 SAVE_4_IN_GENERIC_REGISTER;
346 case MONO_TYPE_VALUETYPE:
347 if (sig->params [i]->data.klass->enumtype) {
348 simpletype = sig->params [i]->data.klass->enum_basetype->type;
351 if (mono_class_value_size (sig->params [i]->data.klass, NULL) != 4)
352 g_error ("can only marshal enums, not generic structures (size: %d)",
353 mono_class_value_size (sig->params [i]->data.klass, NULL));
354 if (gr < GENERAL_REGS) {
355 ppc_lwz (p, ppc_r3 + gr, i*16, ARG_BASE);
356 ppc_lwz (p, ppc_r3 + gr, 0, ppc_r3 + gr);
359 NOT_IMPLEMENTED ("save value type on stack");
362 case MONO_TYPE_STRING:
363 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || runtime) {
364 SAVE_4_IN_GENERIC_REGISTER;
367 ppc_lwz (p, ppc_r3 + gr, stack_size - 20 - act_strs, ppc_r31);
371 NOT_IMPLEMENTED ("string on stack");
378 g_warning ("check endianess");
379 ppc_lwz (p, ppc_r3 + gr, i*16, ARG_BASE);
381 ppc_lwz (p, ppc_r3 + gr, i*17, ARG_BASE);
384 NOT_IMPLEMENTED ("i8 on stack");
389 ppc_lfs (p, ppc_f1 + fr, i*16, ARG_BASE);
392 NOT_IMPLEMENTED ("r4 on stack");
397 ppc_lfd (p, ppc_f1 + fr, i*16, ARG_BASE);
400 NOT_IMPLEMENTED ("r8 on stack");
404 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
411 static inline guint8 *
412 alloc_code_memory (guint code_size)
417 p = g_malloc (code_size + PAGESIZE - 1);
419 /* Align to a multiple of PAGESIZE, assumed to be a power of two */
420 p = (char *)(((int) p + PAGESIZE-1) & ~(PAGESIZE-1));
422 p = g_malloc (code_size);
424 printf (" align: %p (%d)\n", p, (guint)p % 4);
430 mono_string_new_wrapper (const char *text)
432 return text ? mono_string_new (mono_domain_get (), text) : NULL;
435 static inline guint8 *
436 emit_call_and_store_retval (guint8 *p, MonoMethod *method, guint strings, gint runtime)
438 MonoMethodSignature *sig = method->signature;
442 ppc_mtlr (p, strings ? ppc_r29 : ppc_r0);
445 /* get return value */
446 if (sig->ret->byref) {
447 ppc_lwz (p, ppc_r9, 8, ppc_r31); /* load "retval" address */
448 ppc_stw (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
450 simpletype = sig->ret->type;
452 switch (simpletype) {
453 case MONO_TYPE_BOOLEAN:
456 ppc_lwz (p, ppc_r9, 8, ppc_r31); /* load "retval" address */
457 ppc_stb (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
462 ppc_lwz (p, ppc_r9, 8, ppc_r31); /* load "retval" address */
463 ppc_sth (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
469 case MONO_TYPE_CLASS:
470 case MONO_TYPE_OBJECT:
471 case MONO_TYPE_SZARRAY:
472 case MONO_TYPE_ARRAY:
473 ppc_lwz (p, ppc_r9, 8, ppc_r31); /* load "retval" address */
474 ppc_stw (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
476 case MONO_TYPE_STRING:
477 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && !runtime) {
478 ppc_lis (p, ppc_r0, (guint32) mono_string_new_wrapper >> 16);
479 ppc_ori (p, ppc_r0, ppc_r0, (guint32) mono_string_new_wrapper & 0xffff);
480 ppc_mtlr (p, ppc_r0);
484 ppc_lwz (p, ppc_r9, 8, ppc_r31); /* load "retval" address */
485 ppc_stw (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
489 ppc_lwz (p, ppc_r9, 8, ppc_r31); /* load "retval" address */
490 ppc_stfs (p, ppc_f1, 0, ppc_r9); /* save return value (f1) to "retval" */
493 ppc_lwz (p, ppc_r9, 8, ppc_r31); /* load "retval" address */
494 ppc_stfd (p, ppc_f1, 0, ppc_r9); /* save return value (f1) to "retval" */
497 g_warning ("check endianess");
498 ppc_lwz (p, ppc_r9, 8, ppc_r31); /* load "retval" address */
499 ppc_stw (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
500 ppc_stw (p, ppc_r4, 4, ppc_r9); /* save return value (r3) to "retval" */
502 case MONO_TYPE_VALUETYPE:
503 if (sig->ret->data.klass->enumtype) {
504 simpletype = sig->ret->data.klass->enum_basetype->type;
507 NOT_IMPLEMENTED ("retval valuetype");
512 g_error ("Can't handle as return value 0x%x", sig->ret->type);
519 static inline guint8 *
520 emit_epilog (guint8 *p, MonoMethod *method, guint stack_size, guint strings, gboolean runtime)
523 MonoMethodSignature *sig = method->signature;
526 /* free allocated memory */
528 for (i = 0; i < sig->param_count; ++i) {
529 if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_STRING
530 && !((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || runtime)) {
531 ppc_lis (p, ppc_r0, (guint32) g_free >> 16);
532 ppc_lwz (p, ppc_r3, stack_size - 20 - act_strs, ppc_r31);
533 ppc_ori (p, ppc_r0, ppc_r0, (guint32) g_free & 0xffff);
534 ppc_mtlr (p, ppc_r0);
540 /* restore volatile registers */
541 ppc_lwz (p, ppc_r30, stack_size - 16, ppc_r1);
542 ppc_lwz (p, ppc_r29, stack_size - 12, ppc_r1);
543 if (method->signature->hasthis) {
544 ppc_lwz (p, ppc_r28, 24, ppc_r1);
548 /* function epilog */
549 ppc_lwz (p, ppc_r11, 0, ppc_r1); /* r11 <--- sp[0] load backchain from caller's function */
550 ppc_lwz (p, ppc_r0, 4, ppc_r11); /* r0 <--- r11[4] load return address */
551 ppc_mtlr (p, ppc_r0); /* LR <--- r0 set return address */
552 ppc_lwz (p, ppc_r31, -4, ppc_r11); /* r31 <--- r11[-4] restore r31 */
553 ppc_mr (p, ppc_r1, ppc_r11); /* sp <--- r11 restore stack */
554 ppc_blr (p); /* return */
560 mono_create_trampoline (MonoMethod *method, int runtime)
562 guint8 *p, *code_buffer;
563 guint stack_size, code_size, strings;
565 printf ("\nPInvoke [start emiting] %s\n", method->name);
566 calculate_sizes (method, &stack_size, &code_size, &strings, runtime);
568 p = code_buffer = alloc_code_memory (code_size);
569 p = emit_prolog (p, method, stack_size, strings);
570 p = emit_save_parameters (p, method, stack_size, strings, runtime);
571 p = emit_call_and_store_retval (p, method, strings, runtime);
572 p = emit_epilog (p, method, stack_size, strings, runtime);
576 printf (".text\n.align 4\n.globl main\n.type main,@function\nmain:\n");
577 for (cp = code_buffer; cp < p; cp++) {
578 printf (".byte 0x%x\n", *cp);
583 if (mprotect (code_buffer, 1024, PROT_READ | PROT_WRITE | PROT_EXEC)) {
584 g_error ("Cannot mprotect trampoline\n");
588 printf ("emited code size: %d\n", p - code_buffer);
589 flush_icache (code_buffer, p - code_buffer);
591 printf ("PInvoke [end emiting]\n");
593 return (MonoPIFunc) code_buffer;
594 /* return fake_func; */
598 #define MINV_POS (- sizeof (MonoInvocation))
599 #define STACK_POS (MINV_POS - sizeof (stackval) * sig->param_count)
601 #define TYPE_OFFSET (G_STRUCT_OFFSET (stackval, type))
604 * Returns a pointer to a native function that can be used to
605 * call the specified method.
606 * The function created will receive the arguments according
607 * to the call convention specified in the method.
608 * This function works by creating a MonoInvocation structure,
609 * filling the fields in and calling ves_exec_method on it.
610 * Still need to figure out how to handle the exception stuff
611 * across the managed/unmanaged boundary.
614 mono_create_method_pointer (MonoMethod *method)
621 * mono_create_method_pointer () will insert a pointer to the MonoMethod
622 * so that the interp can easily get at the data: this function will retrieve
623 * the method from the code stream.
626 mono_method_pointer_get (void *code)