#include "mini.h"
#include "mini-ppc.h"
-typedef enum {
- MONO_TRAMPOLINE_GENERIC,
- MONO_TRAMPOLINE_JUMP,
- MONO_TRAMPOLINE_CLASS_INIT
-} MonoTrampolineType;
-
-/* adapt to mini later... */
-#define mono_jit_share_code (1)
-
-/*
- * Address of the x86 trampoline code. This is used by the debugger to check
- * whether a method is a trampoline.
- */
-guint8 *mono_generic_trampoline_code = NULL;
-
/*
* get_unbox_trampoline:
* @m: method pointer
guint8 *code, *start;
int this_pos = 3;
- if (!m->signature->ret->byref && MONO_TYPE_ISSTRUCT (m->signature->ret))
+ if (!mono_method_signature (m)->ret->byref && MONO_TYPE_ISSTRUCT (mono_method_signature (m)->ret))
this_pos = 4;
start = code = g_malloc (20);
/* Stack size for trampoline function
* PPC_MINIMAL_STACK_SIZE + 16 (args + alignment to ppc_magic_trampoline)
- * 32 * 4 gregs + 13 * 8 fregs
+ * + MonoLMF + 14 fp regs + 13 gregs + alignment
+ * #define STACK (PPC_MINIMAL_STACK_SIZE + 4 * sizeof (gulong) + sizeof (MonoLMF) + 14 * sizeof (double) + 13 * (sizeof (gulong)))
+ * STACK would be 444 for 32 bit darwin
*/
-#define STACK (320)
+#define STACK (448)
/* Method-specific trampoline code fragment size */
#define METHOD_TRAMPOLINE_SIZE 64
static gpointer
ppc_magic_trampoline (MonoMethod *method, guint32 *code, char *sp)
{
- char *o, *start;
+ char *o = NULL;
gpointer addr;
+ MonoJitInfo *ji, *target_ji;
int reg, offset = 0;
addr = mono_compile_method(method);
return addr;
}
+ /* We can't trampoline across domains */
+ ji = mono_jit_info_table_find (mono_domain_get (), code);
+ target_ji = mono_jit_info_table_find (mono_domain_get (), addr);
+ if (!mono_method_same_domain (ji, target_ji))
+ return addr;
+
/* Locate the address of the method-specific trampoline. The call using
the vtable slot that took the processing flow to 'arch_create_jit_trampoline'
looks something like this:
*/
if (((*code) >> 26) == 18) {
/*g_print ("direct patching\n");*/
- ppc_patch (code, addr);
- mono_arch_flush_icache (code, 4);
+ ppc_patch ((char*)code, addr);
+ mono_arch_flush_icache ((char*)code, 4);
return addr;
}
/* Sanity check: instruction must be 'blrl' */
g_assert(*code == 0x4e800021);
-
+
+ /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
+ if ((code [-1] >> 26) == 31 && (code [-2] >> 26) == 24 && (code [-3] >> 26) == 15) {
+ ppc_patch ((char*)code, addr);
+ return addr;
+ }
+
/* OK, we're now at the 'blrl' instruction. Now walk backwards
till we get to a 'mtlr rA' */
for(; --code;) {
if((*code & 0x7c0803a6) == 0x7c0803a6) {
gint16 soff;
+ gint reg_offset;
/* Here we are: we reached the 'mtlr rA'.
Extract the register from the instruction */
reg = (*code & 0x03e00000) >> 21;
soff = (*code & 0xffff);
offset = soff;
reg = (*code >> 16) & 0x1f;
+ g_assert (reg != ppc_r1);
/*g_print ("patching reg is %d\n", reg);*/
- switch(reg) {
- case 0 : o = *((int *) (sp + STACK - 8)); break;
- case 3 : o = *((int *) (sp + STACK - 12)); break;
- case 4 : o = *((int *) (sp + STACK - 16)); break;
- case 5 : o = *((int *) (sp + STACK - 20)); break;
- case 6 : o = *((int *) (sp + STACK - 24)); break;
- case 7 : o = *((int *) (sp + STACK - 28)); break;
- case 8 : o = *((int *) (sp + STACK - 32)); break;
- case 9 : o = *((int *) (sp + STACK - 36)); break;
- case 10: o = *((int *) (sp + STACK - 40)); break;
- case 11: o = *((int *) (sp + STACK - 44)); break;
- case 12: o = *((int *) (sp + STACK - 48)); break;
- case 13: o = *((int *) (sp + STACK - 52)); break;
- case 14: o = *((int *) (sp + STACK - 56)); break;
- case 15: o = *((int *) (sp + STACK - 60)); break;
- case 16: o = *((int *) (sp + STACK - 64)); break;
- case 17: o = *((int *) (sp + STACK - 68)); break;
- case 18: o = *((int *) (sp + STACK - 72)); break;
- case 19: o = *((int *) (sp + STACK - 76)); break;
- case 20: o = *((int *) (sp + STACK - 80)); break;
- case 21: o = *((int *) (sp + STACK - 84)); break;
- case 22: o = *((int *) (sp + STACK - 88)); break;
- case 23: o = *((int *) (sp + STACK - 92)); break;
- case 24: o = *((int *) (sp + STACK - 96)); break;
- case 25: o = *((int *) (sp + STACK - 100)); break;
- case 26: o = *((int *) (sp + STACK - 104)); break;
- case 27: o = *((int *) (sp + STACK - 108)); break;
- case 28: o = *((int *) (sp + STACK - 112)); break;
- case 29: o = *((int *) (sp + STACK - 116)); break;
- case 30: o = *((int *) (sp + STACK - 120)); break;
- case 31: o = *((int *) (sp + STACK - 4)); break;
- default:
- printf("%s: Unexpected register %d\n",
- __FUNCTION__, reg);
- g_assert_not_reached();
+ if (reg >= 13) {
+ /* saved in the MonoLMF structure */
+ reg_offset = STACK - sizeof (MonoLMF) + G_STRUCT_OFFSET (MonoLMF, iregs);
+ reg_offset += (reg - 13) * sizeof (gulong);
+ } else {
+ /* saved in the stack, see frame diagram below */
+ reg_offset = STACK - sizeof (MonoLMF) - (14 * sizeof (double)) - (13 * sizeof (gulong));
+ reg_offset += reg * sizeof (gulong);
}
+ /* o contains now the value of register reg */
+ o = *((char**) (sp + reg_offset));
break;
}
}
we won't have an object, but the actual pointer to the
valuetype as the this argument
*/
- if (method->klass->valuetype)
+ if (method->klass->valuetype && !mono_aot_is_got_entry (code, o))
addr = get_unbox_trampoline (method, addr);
o += offset;
- *((gpointer *)o) = addr;
- return addr;
- /* Finally, replace the method-specific trampoline code (which called
- the generic trampoline code) with a fragment that calls directly the
- compiled method */
-
- start = o;
-#if 1
- /* FIXME: make the patching thread safe */
- ppc_b (o, 0);
- ppc_patch (o - 4, addr);
- /*g_print ("patching at %p to %p\n", o, addr);*/
-#else
- ppc_stwu (o, ppc_r1, -16, ppc_r1);
- ppc_mflr (o, ppc_r0);
- ppc_stw (o, ppc_r31, 12, ppc_r1);
- ppc_stw (o, ppc_r0, 20, ppc_r1);
- ppc_mr (o, ppc_r31, ppc_r1);
-
- ppc_lis (o, ppc_r0, (guint32) addr >> 16);
- ppc_ori (o, ppc_r0, ppc_r0, (guint32) addr & 0xffff);
- ppc_mtlr (o, ppc_r0);
- ppc_blrl (o);
-
- ppc_lwz (o, ppc_r11, 0, ppc_r1);
- ppc_lwz (o, ppc_r0, 4, ppc_r11);
- ppc_mtlr (o, ppc_r0);
- ppc_lwz (o, ppc_r31, -4, ppc_r11);
- ppc_mr (o, ppc_r1, ppc_r11);
- ppc_blr (o);
-#endif
- mono_arch_flush_icache (start, o - start);
- g_assert(o - start < METHOD_TRAMPOLINE_SIZE);
-
+ if (mono_aot_is_got_entry (code, o) || mono_domain_owns_vtable_slot (mono_domain_get (), o))
+ *((gpointer *)o) = addr;
return addr;
}
#endif
}
-static guchar*
-create_trampoline_code (MonoTrampolineType tramp_type)
+/*
+ * Stack frame description when the generic trampoline is called.
+ * caller frame
+ * --------------------
+ * MonoLMF
+ * -------------------
+ * Saved FP registers 0-13
+ * -------------------
+ * Saved general registers 0-12
+ * -------------------
+ * param area for 3 args to ppc_magic_trampoline
+ * -------------------
+ * linkage area
+ * -------------------
+ */
+guchar*
+mono_arch_create_trampoline_code (MonoTrampolineType tramp_type)
{
guint8 *buf, *code = NULL;
- static guint8* generic_jump_trampoline = NULL;
- static guint8 *generic_class_init_trampoline = NULL;
int i, offset;
- switch (tramp_type) {
- case MONO_TRAMPOLINE_GENERIC:
- if (mono_generic_trampoline_code)
- return mono_generic_trampoline_code;
- break;
- case MONO_TRAMPOLINE_JUMP:
- if (generic_jump_trampoline)
- return generic_jump_trampoline;
- break;
- case MONO_TRAMPOLINE_CLASS_INIT:
- if (generic_class_init_trampoline)
- return generic_class_init_trampoline;
- break;
- }
-
if(!code) {
/* Now we'll create in 'buf' the PowerPC trampoline code. This
is the trampoline code common to all methods */
code = buf = g_malloc(512);
- /*-----------------------------------------------------------
- STEP 0: First create a non-standard function prologue with a
- stack size big enough to save our registers:
-
- lr (We'll be calling functions here, so we
- must save it)
- r0 (See ppc_magic_trampoline)
- r1 (sp) (Stack pointer - must save)
- r3-r10 Function arguments.
- r11-r31 (See ppc_magic_trampoline)
- method in r11 (See ppc_magic_trampoline)
-
- This prologue is non-standard because r0 is not saved here - it
- was saved in the method-specific trampoline code
- -----------------------------------------------------------*/
-
ppc_stwu (buf, ppc_r1, -STACK, ppc_r1);
-
- /* Save r0 before modifying it - we will need its contents in
- 'ppc_magic_trampoline' */
- ppc_stw (buf, ppc_r0, STACK - 8, ppc_r1);
-
- ppc_stw (buf, ppc_r31, STACK - 4, ppc_r1);
- ppc_mr (buf, ppc_r31, ppc_r1);
-
- /* Now save our registers. */
- ppc_stw (buf, ppc_r3, STACK - 12, ppc_r1);
- ppc_stw (buf, ppc_r4, STACK - 16, ppc_r1);
- ppc_stw (buf, ppc_r5, STACK - 20, ppc_r1);
- ppc_stw (buf, ppc_r6, STACK - 24, ppc_r1);
- ppc_stw (buf, ppc_r7, STACK - 28, ppc_r1);
- ppc_stw (buf, ppc_r8, STACK - 32, ppc_r1);
- ppc_stw (buf, ppc_r9, STACK - 36, ppc_r1);
- ppc_stw (buf, ppc_r10, STACK - 40, ppc_r1);
- /* STACK - 44 contains r11, which is set in the method-specific
- part of the trampoline (see bellow this 'if' block) */
- ppc_stw (buf, ppc_r12, STACK - 48, ppc_r1);
- ppc_stw (buf, ppc_r13, STACK - 52, ppc_r1);
- ppc_stw (buf, ppc_r14, STACK - 56, ppc_r1);
- ppc_stw (buf, ppc_r15, STACK - 60, ppc_r1);
- ppc_stw (buf, ppc_r16, STACK - 64, ppc_r1);
- ppc_stw (buf, ppc_r17, STACK - 68, ppc_r1);
- ppc_stw (buf, ppc_r18, STACK - 72, ppc_r1);
- ppc_stw (buf, ppc_r19, STACK - 76, ppc_r1);
- ppc_stw (buf, ppc_r20, STACK - 80, ppc_r1);
- ppc_stw (buf, ppc_r21, STACK - 84, ppc_r1);
- ppc_stw (buf, ppc_r22, STACK - 88, ppc_r1);
- ppc_stw (buf, ppc_r23, STACK - 92, ppc_r1);
- ppc_stw (buf, ppc_r24, STACK - 96, ppc_r1);
- ppc_stw (buf, ppc_r25, STACK - 100, ppc_r1);
- ppc_stw (buf, ppc_r26, STACK - 104, ppc_r1);
- ppc_stw (buf, ppc_r27, STACK - 108, ppc_r1);
- ppc_stw (buf, ppc_r28, STACK - 112, ppc_r1);
- ppc_stw (buf, ppc_r29, STACK - 116, ppc_r1);
- ppc_stw (buf, ppc_r30, STACK - 120, ppc_r1);
- /* Save 'method' pseudo-parameter - the one passed in r11 */
- ppc_stw (buf, ppc_r11, STACK - 124, ppc_r1);
-
- /* Save the FP registers */
- offset = 124 + 4 + 8;
- for (i = ppc_f1; i <= PPC_LAST_FPARG_REG; ++i) {
- ppc_stfd (buf, i, STACK - offset, ppc_r1);
- offset += 8;
- }
- /*----------------------------------------------------------
- STEP 1: call 'mono_get_lmf_addr()' to get the address of our
- LMF. We'll need to restore it after the call to
- 'ppc_magic_trampoline' and before the call to the native
- method.
- ----------------------------------------------------------*/
-
- /* Calculate the address and make the call. Keep in mind that
- we're using r0, so we'll have to restore it before calling
- 'ppc_magic_trampoline' */
- ppc_lis (buf, ppc_r0, (guint32) mono_get_lmf_addr >> 16);
- ppc_ori (buf, ppc_r0, ppc_r0, (guint32) mono_get_lmf_addr & 0xffff);
+ /* start building the MonoLMF on the stack */
+ offset = STACK - sizeof (double) * MONO_SAVED_FREGS;
+ for (i = 14; i < 32; i++) {
+ ppc_stfd (buf, i, offset, ppc_r1);
+ offset += sizeof (double);
+ }
+ /*
+ * now the integer registers. r13 is already saved in the trampoline,
+ * and at this point contains the method to compile, so we skip it.
+ */
+ offset = STACK - sizeof (MonoLMF) + G_STRUCT_OFFSET (MonoLMF, iregs) + sizeof (gulong);
+ ppc_stmw (buf, ppc_r14, ppc_r1, offset);
+
+ /* Now save the rest of the registers below the MonoLMF struct, first 14
+ * fp regs and then the 13 gregs.
+ */
+ offset = STACK - sizeof (MonoLMF) - (14 * sizeof (double));
+ for (i = 0; i < 14; i++) {
+ ppc_stfd (buf, i, offset, ppc_r1);
+ offset += sizeof (double);
+ }
+ offset = STACK - sizeof (MonoLMF) - (14 * sizeof (double)) - (13 * sizeof (gulong));
+ for (i = 0; i < 13; i++) {
+ ppc_stw (buf, i, offset, ppc_r1);
+ offset += sizeof (gulong);
+ }
+ /* we got here through a jump to the ctr reg, we must save the lr
+ * in the parent frame (we do it here to reduce the size of the
+ * method-specific trampoline)
+ */
+ ppc_mflr (buf, ppc_r0);
+ ppc_stw (buf, ppc_r0, STACK + PPC_RET_ADDR_OFFSET, ppc_r1);
+
+ /* ok, now we can continue with the MonoLMF setup, mostly untouched
+ * from emit_prolog in mini-ppc.c
+ */
+ ppc_load (buf, ppc_r0, mono_get_lmf_addr);
ppc_mtlr (buf, ppc_r0);
ppc_blrl (buf);
+ /* we build the MonoLMF structure on the stack - see mini-ppc.h
+ * The pointer to the struct is put in ppc_r11.
+ */
+ ppc_addi (buf, ppc_r11, ppc_sp, STACK - sizeof (MonoLMF));
+ ppc_stw (buf, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
+ /* new_lmf->previous_lmf = *lmf_addr */
+ ppc_lwz (buf, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
+ ppc_stw (buf, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
+ /* *(lmf_addr) = r11 */
+ ppc_stw (buf, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
+ /* save method info (it's in r13) */
+ ppc_stw (buf, ppc_r13, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
+ ppc_stw (buf, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
+ /* save the IP (caller ip) */
+ if (tramp_type == MONO_TRAMPOLINE_JUMP) {
+ ppc_li (buf, ppc_r0, 0);
+ } else {
+ ppc_lwz (buf, ppc_r0, STACK + PPC_RET_ADDR_OFFSET, ppc_r1);
+ }
+ ppc_stw (buf, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
- /* XXX Update LMF !!! */
-
- /*----------------------------------------------------------
- STEP 2: call 'ppc_magic_trampoline()', who will compile the
- code and fix the method vtable entry for us
- ----------------------------------------------------------*/
-
- /* Set arguments */
-
- /* Arg 1: MonoMethod *method. It was put in r11 by the
- method-specific trampoline code, and then saved before the call
- to mono_get_lmf_addr()'. Restore r11, by the way :-) */
- ppc_lwz (buf, ppc_r3, STACK - 124, ppc_r1);
- ppc_lwz (buf, ppc_r11, STACK - 44, ppc_r1);
+ /*
+ * Now we're ready to call ppc_magic_trampoline ().
+ */
+ /* Arg 1: MonoMethod *method. It was put in r13 */
+ ppc_mr (buf, ppc_r3, ppc_r13);
/* Arg 2: code (next address to the instruction that called us) */
if (tramp_type == MONO_TRAMPOLINE_JUMP) {
ppc_lwz (buf, ppc_r4, STACK + PPC_RET_ADDR_OFFSET, ppc_r1);
}
- /* Arg 3: stack pointer */
+ /* Arg 3: stack pointer so that the magic trampoline can access the
+ * registers we saved above
+ */
ppc_mr (buf, ppc_r5, ppc_r1);
- /* Calculate call address, restore r0 and call
- 'ppc_magic_trampoline'. Return value will be in r3 */
if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT) {
ppc_lis (buf, ppc_r0, (guint32) ppc_class_init_trampoline >> 16);
ppc_ori (buf, ppc_r0, ppc_r0, (guint32) ppc_class_init_trampoline & 0xffff);
ppc_ori (buf, ppc_r0, ppc_r0, (guint32) ppc_magic_trampoline & 0xffff);
}
ppc_mtlr (buf, ppc_r0);
- ppc_lwz (buf, ppc_r0, STACK - 8, ppc_r1);
ppc_blrl (buf);
- /* OK, code address is now on r3. Move it to r0, so that we
- can restore r3 and use it from r0 later */
- ppc_mr (buf, ppc_r0, ppc_r3);
-
+ /* OK, code address is now on r3. Move it to the counter reg
+ * so it will be ready for the final jump: this is safe since we
+ * won't do any more calls.
+ */
+ ppc_mtctr (buf, ppc_r3);
+
+ /*
+ * Now we restore the MonoLMF (see emit_epilogue in mini-ppc.c)
+ * and the rest of the registers, so the method called will see
+ * the same state as before we executed.
+ * The pointer to MonoLMF is in ppc_r11.
+ */
+ ppc_addi (buf, ppc_r11, ppc_r1, STACK - sizeof (MonoLMF));
+ /* r5 = previous_lmf */
+ ppc_lwz (buf, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
+ /* r6 = lmf_addr */
+ ppc_lwz (buf, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
+ /* *(lmf_addr) = previous_lmf */
+ ppc_stw (buf, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
+ /* restore iregs: this time include r13 */
+ ppc_lmw (buf, ppc_r13, ppc_r11, G_STRUCT_OFFSET(MonoLMF, iregs));
+ /* restore fregs */
+ for (i = 14; i < 32; i++) {
+ ppc_lfd (buf, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
+ }
- /*----------------------------------------------------------
- STEP 3: Restore the LMF
- ----------------------------------------------------------*/
-
- /* XXX Do it !!! */
-
- /*----------------------------------------------------------
- STEP 4: call the compiled method
- ----------------------------------------------------------*/
-
- /* Restore registers */
-
- ppc_lwz (buf, ppc_r3, STACK - 12, ppc_r1);
- ppc_lwz (buf, ppc_r4, STACK - 16, ppc_r1);
- ppc_lwz (buf, ppc_r5, STACK - 20, ppc_r1);
- ppc_lwz (buf, ppc_r6, STACK - 24, ppc_r1);
- ppc_lwz (buf, ppc_r7, STACK - 28, ppc_r1);
- ppc_lwz (buf, ppc_r8, STACK - 32, ppc_r1);
- ppc_lwz (buf, ppc_r9, STACK - 36, ppc_r1);
- ppc_lwz (buf, ppc_r10, STACK - 40, ppc_r1);
- ppc_lwz (buf, ppc_r11, STACK - 44, ppc_r1);
- ppc_lwz (buf, ppc_r12, STACK - 48, ppc_r1);
- ppc_stw (buf, ppc_r13, STACK - 52, ppc_r1);
-
- /* Restore the FP registers */
- offset = 124 + 4 + 8;
- for (i = ppc_f1; i <= PPC_LAST_FPARG_REG; ++i) {
- ppc_lfd (buf, i, STACK - offset, ppc_r1);
- offset += 8;
+ /* restore the volatile registers, we skip r1, of course */
+ offset = STACK - sizeof (MonoLMF) - (14 * sizeof (double));
+ for (i = 0; i < 14; i++) {
+ ppc_lfd (buf, i, offset, ppc_r1);
+ offset += sizeof (double);
+ }
+ offset = STACK - sizeof (MonoLMF) - (14 * sizeof (double)) - (13 * sizeof (gulong));
+ ppc_lwz (buf, ppc_r0, offset, ppc_r1);
+ offset += 2 * sizeof (gulong);
+ for (i = 2; i < 13; i++) {
+ ppc_lwz (buf, i, offset, ppc_r1);
+ offset += sizeof (gulong);
}
- /* We haven't touched any of these, so there's no need to
- restore them */
-
- ppc_lwz (buf, ppc_r14, STACK - 56, ppc_r1);
- ppc_lwz (buf, ppc_r15, STACK - 60, ppc_r1);
- ppc_lwz (buf, ppc_r16, STACK - 64, ppc_r1);
- ppc_lwz (buf, ppc_r17, STACK - 68, ppc_r1);
- ppc_lwz (buf, ppc_r18, STACK - 72, ppc_r1);
- ppc_lwz (buf, ppc_r19, STACK - 76, ppc_r1);
- ppc_lwz (buf, ppc_r20, STACK - 80, ppc_r1);
- ppc_lwz (buf, ppc_r21, STACK - 84, ppc_r1);
- ppc_lwz (buf, ppc_r22, STACK - 88, ppc_r1);
- ppc_lwz (buf, ppc_r23, STACK - 92, ppc_r1);
- ppc_lwz (buf, ppc_r24, STACK - 96, ppc_r1);
- ppc_lwz (buf, ppc_r25, STACK - 100, ppc_r1);
- ppc_lwz (buf, ppc_r26, STACK - 104, ppc_r1);
- ppc_lwz (buf, ppc_r27, STACK - 108, ppc_r1);
- ppc_lwz (buf, ppc_r28, STACK - 112, ppc_r1);
- ppc_lwz (buf, ppc_r29, STACK - 116, ppc_r1);
- ppc_lwz (buf, ppc_r30, STACK - 120, ppc_r1);
- ppc_lwz (buf, ppc_r31, STACK - 4, ppc_r1);
-
/* Non-standard function epilogue. Instead of doing a proper
- return, we just call the compiled code, so
- that, when it finishes, the method returns here. */
-
-#if 1
- /* Restore stack pointer, r31, LR and jump to the code */
+ * return, we just hump to the compiled code.
+ */
+ /* Restore stack pointer and LR and jump to the code */
ppc_lwz (buf, ppc_r1, 0, ppc_r1);
- //ppc_lwz (buf, ppc_r31, -4, ppc_r1);
ppc_lwz (buf, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_r1);
ppc_mtlr (buf, ppc_r11);
- ppc_mtctr (buf, ppc_r0);
ppc_bcctr (buf, 20, 0);
-#else
- ppc_mtlr (buf, ppc_r0);
- ppc_blrl (buf);
-
- /* Restore stack pointer, r31, LR and return to caller */
- ppc_lwz (buf, ppc_r11, 0, ppc_r1);
- ppc_lwz (buf, ppc_r31, -4, ppc_r11);
- ppc_mr (buf, ppc_r1, ppc_r11);
- ppc_lwz (buf, ppc_r0, 4, ppc_r1);
- ppc_mtlr (buf, ppc_r0);
- ppc_blr (buf);
-#endif
-
+
/* Flush instruction cache, since we've generated code */
mono_arch_flush_icache (code, buf - code);
g_assert ((buf - code) <= 512);
}
- switch (tramp_type) {
- case MONO_TRAMPOLINE_GENERIC:
- mono_generic_trampoline_code = code;
- break;
- case MONO_TRAMPOLINE_JUMP:
- generic_jump_trampoline = code;
- break;
- case MONO_TRAMPOLINE_CLASS_INIT:
- generic_class_init_trampoline = code;
- break;
- }
-
return code;
}
-MonoJitInfo*
-mono_arch_create_jump_trampoline (MonoMethod *method)
-{
- guint8 *code, *buf, *tramp = NULL;
+static MonoJitInfo*
+create_specific_tramp (MonoMethod *method, guint8* tramp, MonoDomain *domain) {
+ guint8 *code, *buf;
MonoJitInfo *ji;
- MonoDomain* domain = mono_domain_get ();
-
- tramp = create_trampoline_code (MONO_TRAMPOLINE_JUMP);
mono_domain_lock (domain);
- code = buf = mono_code_manager_reserve (domain->code_mp, METHOD_TRAMPOLINE_SIZE);
+ code = buf = mono_code_manager_reserve (domain->code_mp, 32);
mono_domain_unlock (domain);
- /* Save r11. There's nothing magic in the '44', its just an arbitrary
- position - see above */
- ppc_stw (buf, ppc_r11, -44, ppc_r1);
-
- /* Now save LR - we'll overwrite it now */
- ppc_mflr (buf, ppc_r11);
- ppc_stw (buf, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_r1);
+ /* Save r13 in the place it will have in the on-stack MonoLMF */
+ ppc_stw (buf, ppc_r13, -(MONO_SAVED_FREGS * 8 + MONO_SAVED_GREGS * sizeof (gpointer)), ppc_r1);
/* Prepare the jump to the generic trampoline code.*/
- ppc_lis (buf, ppc_r11, (guint32) tramp >> 16);
- ppc_ori (buf, ppc_r11, ppc_r11, (guint32) tramp & 0xffff);
- ppc_mtlr (buf, ppc_r11);
+ ppc_lis (buf, ppc_r13, (guint32) tramp >> 16);
+ ppc_ori (buf, ppc_r13, ppc_r13, (guint32) tramp & 0xffff);
+ ppc_mtctr (buf, ppc_r13);
- /* And finally put 'method' in r11 and fly! */
- ppc_lis (buf, ppc_r11, (guint32) method >> 16);
- ppc_ori (buf, ppc_r11, ppc_r11, (guint32) method & 0xffff);
- ppc_blr (buf);
+ /* And finally put 'method' in r13 and fly! */
+ ppc_lis (buf, ppc_r13, (guint32) method >> 16);
+ ppc_ori (buf, ppc_r13, ppc_r13, (guint32) method & 0xffff);
+ ppc_bcctr (buf, 20, 0);
/* Flush instruction cache, since we've generated code */
mono_arch_flush_icache (code, buf - code);
- g_assert ((buf - code) <= JUMP_TRAMPOLINE_SIZE);
+ g_assert ((buf - code) <= 32);
ji = g_new0 (MonoJitInfo, 1);
ji->method = method;
return ji;
}
+MonoJitInfo*
+mono_arch_create_jump_trampoline (MonoMethod *method)
+{
+ guint8 *tramp;
+ MonoDomain* domain = mono_domain_get ();
+
+ tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_JUMP);
+ return create_specific_tramp (method, tramp, domain);
+}
+
/**
* arch_create_jit_trampoline:
* @method: pointer to the method info
gpointer
mono_arch_create_jit_trampoline (MonoMethod *method)
{
- guint8 *code, *buf;
- static guint8 *vc = NULL;
+ guint8 *tramp;
+ MonoJitInfo *ji;
MonoDomain* domain = mono_domain_get ();
+ gpointer code_start;
- /* previously created trampoline code */
- if (method->info)
- return method->info;
-
- if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
- return mono_arch_create_jit_trampoline (mono_marshal_get_synchronized_wrapper (method));
-
- vc = create_trampoline_code (MONO_TRAMPOLINE_GENERIC);
-
- /* This is the method-specific part of the trampoline. Its purpose is
- to provide the generic part with the MonoMethod *method pointer. We'll
- use r11 to keep that value, for instance. However, the generic part of
- the trampoline relies on r11 having the same value it had before coming
- here, so we must save it before. */
- //code = buf = g_malloc(METHOD_TRAMPOLINE_SIZE);
- // FIXME: should pass the domain down tot his function
- mono_domain_lock (domain);
- code = buf = mono_code_manager_reserve (domain->code_mp, METHOD_TRAMPOLINE_SIZE);
- mono_domain_unlock (domain);
-
- /* Save r11. There's nothing magic in the '44', its just an arbitrary
- position - see above */
- ppc_stw (buf, ppc_r11, -44, ppc_r1);
-
- /* Now save LR - we'll overwrite it now */
- ppc_mflr (buf, ppc_r11);
- ppc_stw (buf, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_r1);
-
- /* Prepare the jump to the generic trampoline code.*/
- ppc_lis (buf, ppc_r11, (guint32) vc >> 16);
- ppc_ori (buf, ppc_r11, ppc_r11, (guint32) vc & 0xffff);
- ppc_mtlr (buf, ppc_r11);
-
- /* And finally put 'method' in r11 and fly! */
- ppc_lis (buf, ppc_r11, (guint32) method >> 16);
- ppc_ori (buf, ppc_r11, ppc_r11, (guint32) method & 0xffff);
- ppc_blr (buf);
-
- /* Flush instruction cache, since we've generated code */
- mono_arch_flush_icache (code, buf - code);
-
- /* Sanity check */
- g_assert ((buf - code) <= METHOD_TRAMPOLINE_SIZE);
-
- /* Store trampoline address */
- method->info = code;
-
- mono_jit_stats.method_trampolines++;
-
- return code;
-}
-
-#if 0
-
-/**
- * x86_magic_trampoline:
- * @eax: saved x86 register
- * @ecx: saved x86 register
- * @edx: saved x86 register
- * @esi: saved x86 register
- * @edi: saved x86 register
- * @ebx: saved x86 register
- * @code: pointer into caller code
- * @method: the method to translate
- *
- * This method is called by the trampoline functions for virtual
- * methods. It inspects the caller code to find the address of the
- * vtable slot, then calls the JIT compiler and writes the address
- * of the compiled method back to the vtable. All virtual methods
- * are called with: x86_call_membase (inst, basereg, disp). We always
- * use 32 bit displacement to ensure that the length of the call
- * instruction is 6 bytes. We need to get the value of the basereg
- * and the constant displacement.
- */
-static gpointer
-x86_magic_trampoline (int eax, int ecx, int edx, int esi, int edi,
- int ebx, guint8 *code, MonoMethod *m)
-{
- guint8 reg;
- gint32 disp;
- char *o;
- gpointer addr;
-
- addr = mono_compile_method (m);
- g_assert (addr);
-
- /* go to the start of the call instruction
- *
- * address_byte = (m << 6) | (o << 3) | reg
- * call opcode: 0xff address_byte displacement
- * 0xff m=1,o=2 imm8
- * 0xff m=2,o=2 imm32
- */
- code -= 6;
- if ((code [1] != 0xe8) && (code [3] == 0xff) && ((code [4] & 0x18) == 0x10) && ((code [4] >> 6) == 1)) {
- reg = code [4] & 0x07;
- disp = (signed char)code [5];
- } else {
- if ((code [0] == 0xff) && ((code [1] & 0x18) == 0x10) && ((code [1] >> 6) == 2)) {
- reg = code [1] & 0x07;
- disp = *((gint32*)(code + 2));
- } else if ((code [1] == 0xe8)) {
- *((guint32*)(code + 2)) = (guint)addr - ((guint)code + 1) - 5;
- return addr;
- } else if ((code [4] == 0xff) && (((code [5] >> 6) & 0x3) == 0) && (((code [5] >> 3) & 0x7) == 2)) {
- /*
- * This is a interface call: should check the above code can't catch it earlier
- * 8b 40 30 mov 0x30(%eax),%eax
- * ff 10 call *(%eax)
- */
- disp = 0;
- reg = code [5] & 0x07;
- } else {
- printf ("Invalid trampoline sequence: %x %x %x %x %x %x %x\n", code [0], code [1], code [2], code [3],
- code [4], code [5], code [6]);
- g_assert_not_reached ();
- }
- }
-
- switch (reg) {
- case X86_EAX:
- o = (gpointer)eax;
- break;
- case X86_EDX:
- o = (gpointer)edx;
- break;
- case X86_ECX:
- o = (gpointer)ecx;
- break;
- case X86_ESI:
- o = (gpointer)esi;
- break;
- case X86_EDI:
- o = (gpointer)edi;
- break;
- case X86_EBX:
- o = (gpointer)ebx;
- break;
- default:
- g_assert_not_reached ();
- }
-
- o += disp;
-
- if (m->klass->valuetype) {
- return *((gpointer *)o) = get_unbox_trampoline (m, addr);
- } else {
- return *((gpointer *)o) = addr;
- }
-}
-
-/**
- * mono_arch_create_jit_trampoline:
- * @method: pointer to the method info
- *
- * Creates a trampoline function for virtual methods. If the created
- * code is called it first starts JIT compilation of method,
- * and then calls the newly created method. I also replaces the
- * corresponding vtable entry (see x86_magic_trampoline).
- *
- * Returns: a pointer to the newly created code
- */
-gpointer
-mono_arch_create_jit_trampoline (MonoMethod *method)
-{
- guint8 *code, *buf;
+ tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_GENERIC);
+ /* FIXME: should pass the domain down to this function */
+ ji = create_specific_tramp (method, tramp, domain);
+ code_start = ji->code_start;
+ g_free (ji);
- /* previously created trampoline code */
- if (method->info)
- return method->info;
-
- if (!mono_generic_trampoline_code) {
- mono_generic_trampoline_code = buf = g_malloc (256);
- /* save caller save regs because we need to do a call */
- x86_push_reg (buf, X86_EDX);
- x86_push_reg (buf, X86_EAX);
- x86_push_reg (buf, X86_ECX);
-
- /* save LMF begin */
-
- /* save the IP (caller ip) */
- x86_push_membase (buf, X86_ESP, 16);
-
- x86_push_reg (buf, X86_EBX);
- x86_push_reg (buf, X86_EDI);
- x86_push_reg (buf, X86_ESI);
- x86_push_reg (buf, X86_EBP);
-
- /* save method info */
- x86_push_membase (buf, X86_ESP, 32);
- /* get the address of lmf for the current thread */
- x86_call_code (buf, mono_get_lmf_addr);
- /* push lmf */
- x86_push_reg (buf, X86_EAX);
- /* push *lfm (previous_lmf) */
- x86_push_membase (buf, X86_EAX, 0);
- /* *(lmf) = ESP */
- x86_mov_membase_reg (buf, X86_EAX, 0, X86_ESP, 4);
- /* save LFM end */
-
- /* push the method info */
- x86_push_membase (buf, X86_ESP, 44);
- /* push the return address onto the stack */
- x86_push_membase (buf, X86_ESP, 52);
-
- /* save all register values */
- x86_push_reg (buf, X86_EBX);
- x86_push_reg (buf, X86_EDI);
- x86_push_reg (buf, X86_ESI);
- x86_push_membase (buf, X86_ESP, 64); /* EDX */
- x86_push_membase (buf, X86_ESP, 64); /* ECX */
- x86_push_membase (buf, X86_ESP, 64); /* EAX */
-
- x86_call_code (buf, x86_magic_trampoline);
- x86_alu_reg_imm (buf, X86_ADD, X86_ESP, 8*4);
-
- /* restore LMF start */
- /* ebx = previous_lmf */
- x86_pop_reg (buf, X86_EBX);
- /* edi = lmf */
- x86_pop_reg (buf, X86_EDI);
- /* *(lmf) = previous_lmf */
- x86_mov_membase_reg (buf, X86_EDI, 0, X86_EBX, 4);
- /* discard method info */
- x86_pop_reg (buf, X86_ESI);
- /* restore caller saved regs */
- x86_pop_reg (buf, X86_EBP);
- x86_pop_reg (buf, X86_ESI);
- x86_pop_reg (buf, X86_EDI);
- x86_pop_reg (buf, X86_EBX);
- /* discard save IP */
- x86_alu_reg_imm (buf, X86_ADD, X86_ESP, 4);
- /* restore LMF end */
-
- x86_alu_reg_imm (buf, X86_ADD, X86_ESP, 16);
-
- /* call the compiled method */
- x86_jump_reg (buf, X86_EAX);
-
- g_assert ((buf - mono_generic_trampoline_code) <= 256);
- }
-
- code = buf = g_malloc (16);
- x86_push_imm (buf, method);
- x86_jump_code (buf, mono_generic_trampoline_code);
- g_assert ((buf - code) <= 16);
-
- /* store trampoline address */
- method->info = code;
-
- //mono_jit_stats.method_trampolines++;
-
- return code;
+ return code_start;
}
-#endif
-
/**
* mono_arch_create_class_init_trampoline:
* @vtable: the type to initialize
{
guint8 *code, *buf, *tramp;
- tramp = create_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
+ tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
/* This is the method-specific part of the trampoline. Its purpose is
to provide the generic part with the MonoMethod *method pointer. We'll
code = buf = mono_code_manager_reserve (vtable->domain->code_mp, METHOD_TRAMPOLINE_SIZE);
mono_domain_unlock (vtable->domain);
-#if 1
ppc_mflr (buf, ppc_r4);
ppc_stw (buf, ppc_r4, PPC_RET_ADDR_OFFSET, ppc_sp);
- ppc_stwu (buf, ppc_sp, -32, ppc_sp);
+ ppc_stwu (buf, ppc_sp, -64, ppc_sp);
ppc_load (buf, ppc_r3, vtable);
ppc_load (buf, ppc_r5, 0);
ppc_mtlr (buf, ppc_r0);
ppc_blrl (buf);
- ppc_lwz (buf, ppc_r0, 32 + PPC_RET_ADDR_OFFSET, ppc_sp);
- ppc_mtlr (buf, ppc_r0);
- ppc_addic (buf, ppc_sp, ppc_sp, 32);
- ppc_blr (buf);
-#else
- /* Save r11. There's nothing magic in the '44', its just an arbitrary
- position - see above */
- ppc_stw (buf, ppc_r11, -44, ppc_r1);
-
- /* Now save LR - we'll overwrite it now */
- ppc_mflr (buf, ppc_r11);
- ppc_stw (buf, ppc_r11, 4, ppc_r1);
- ppc_stw (buf, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_r1);
-
- /* Prepare the jump to the generic trampoline code.*/
- ppc_lis (buf, ppc_r11, (guint32) tramp >> 16);
- ppc_ori (buf, ppc_r11, ppc_r11, (guint32) tramp & 0xffff);
- ppc_mtlr (buf, ppc_r11);
-
- /* And finally put 'vtable' in r11 and fly! */
- ppc_lis (buf, ppc_r11, (guint32) vtable >> 16);
- ppc_ori (buf, ppc_r11, ppc_r11, (guint32) vtable & 0xffff);
- ppc_blrl (buf);
- ppc_lwz (buf, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_r1);
+ ppc_lwz (buf, ppc_r0, 64 + PPC_RET_ADDR_OFFSET, ppc_sp);
ppc_mtlr (buf, ppc_r0);
+ ppc_addic (buf, ppc_sp, ppc_sp, 64);
ppc_blr (buf);
-#endif
-
/* Flush instruction cache, since we've generated code */
mono_arch_flush_icache (code, buf - code);
if (notification_address)
*notification_address = buf;
ppc_blr (buf);
+ mono_arch_flush_icache (ptr, buf - ptr);
return ptr;
}