X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Ftramp-s390x.c;h=b635e7ce6b706970b1cf440d82c73976771d8813;hb=2d23bfcbce7a3f7e54dcd5911adb88b244baca35;hp=1f2ff611b7d9f3d266fc839c92ff27ff0be9c2f7;hpb=fcdc0a20c951f1ea060af96c206be474fba7089d;p=mono.git diff --git a/mono/mini/tramp-s390x.c b/mono/mini/tramp-s390x.c index 1f2ff611b7d..b635e7ce6b7 100644 --- a/mono/mini/tramp-s390x.c +++ b/mono/mini/tramp-s390x.c @@ -31,8 +31,7 @@ /*------------------------------------------------------------------*/ /* Method-specific trampoline code fragment sizes */ /*------------------------------------------------------------------*/ -#define METHOD_TRAMPOLINE_SIZE 96 -#define JUMP_TRAMPOLINE_SIZE 96 +#define SPECIFIC_TRAMPOLINE_SIZE 96 /*========================= End of Defines =========================*/ @@ -48,7 +47,6 @@ #include #include #include -#include #include "mini.h" #include "mini-s390x.h" @@ -76,7 +74,7 @@ /*------------------------------------------------------------------*/ /* */ -/* Name - get_unbox_trampoline */ +/* Name - mono_arch_get_unbox_trampoline */ /* */ /* Function - Return a pointer to a trampoline which does the */ /* unboxing before calling the method. */ @@ -84,23 +82,24 @@ /* When value type methods are called through the */ /* vtable we need to unbox the 'this' argument. */ /* */ -/* Parameters - method - Methd pointer */ +/* Parameters - gsctx - Generic sharing context */ +/* method - Methd pointer */ /* addr - Pointer to native code for method */ /* */ /*------------------------------------------------------------------*/ -static gpointer -get_unbox_trampoline (MonoMethod *method, gpointer addr) +gpointer +mono_arch_get_unbox_trampoline (MonoGenericSharingContext *gsctx, MonoMethod *method, gpointer addr) { guint8 *code, *start; int this_pos = s390_r2; + MonoDomain *domain = mono_domain_get (); start = addr; - if ((!mono_method_signature (method)->ret->byref) && - (MONO_TYPE_ISSTRUCT (mono_method_signature (method)->ret))) + if (MONO_TYPE_ISSTRUCT (mono_method_signature (method)->ret)) this_pos = s390_r3; - - start = code = mono_global_codeman_reserve (28); + + start = code = mono_domain_code_reserve (domain, 28); s390_basr (code, s390_r1, 0); s390_j (code, 6); @@ -111,6 +110,8 @@ get_unbox_trampoline (MonoMethod *method, gpointer addr) g_assert ((code - start) <= 28); + mono_arch_flush_icache (start, code - start); + return start; } @@ -118,142 +119,73 @@ get_unbox_trampoline (MonoMethod *method, gpointer addr) /*------------------------------------------------------------------*/ /* */ -/* Name - s390_magic_trampoline */ -/* */ -/* Function - This method is called by the function */ -/* "arch_create_jit_trampoline", which in turn is */ -/* called by the trampoline functions for virtual */ -/* methods. After having called the JIT compiler to */ -/* compile the method, it inspects the caller code */ -/* to find the address of the method-specific part */ -/* of the trampoline vtable slot for this method, */ -/* updates it with a fragment that calls the newly */ -/* compiled code and returns this address. The calls */ -/* generated by mono for S/390 will look like either:*/ -/* 1. l %r1,xxx(%rx) */ -/* bras %r14,%r1 */ -/* 2. brasl %r14,xxxxxx */ +/* Name - mono_arch_patch_callsite */ /* */ -/* Parameters - code - Pointer into caller code */ -/* method - The method to compile */ -/* sp - Stack pointer */ +/* Function - Patch a non-virtual callsite so it calls @addr. */ /* */ /*------------------------------------------------------------------*/ -static gpointer -s390_magic_trampoline (MonoMethod *method, guchar *code, char *sp) +void +mono_arch_patch_callsite (guint8 *method_start, guint8 *orig_code, guint8 *addr) { - gpointer addr; - gint64 displace; - guchar reg, lkReg; - guchar *base; + gint32 displace; unsigned short opcode; - MonoJitInfo *codeJi, - *addrJi; - - addr = mono_compile_method(method); - g_assert(addr); - - if (code) { - - codeJi = mono_jit_info_table_find (mono_domain_get(), code); - addrJi = mono_jit_info_table_find (mono_domain_get(), addr); - if (mono_method_same_domain (codeJi, addrJi)) { - - opcode = *((unsigned short *) (code - 6)); - if (opcode == 0xc0e5) { - /* This is the 'brasl' instruction */ - code -= 4; - displace = ((gint64) addr - (gint64) (code - 2)) / 2; - if (mono_method_same_domain (codeJi, addrJi)) { - s390_patch_rel (code, displace); - mono_arch_flush_icache (code, 4); - } - } else { - /*-----------------------------------*/ - /* This is a bras r14,Rz instruction */ - /* If it's preceded by a LG Rx,d(Ry) */ - /* If Rz == 1 then we check if unbox-*/ - /* is required. We patch the address */ - /* by determining the location desc- */ - /* cribed by *Ry+d. */ - /*-----------------------------------*/ - code -= 6; - - /*-----------------------------------*/ - /* If call is preceded by LGR then */ - /* there's nothing to patch */ - /*-----------------------------------*/ - if ((code[0] == 0xb9) && - (code[1] == 0x04)) - return addr; - - /*-----------------------------------*/ - /* We back up until we're pointing at*/ - /* the base/displacement portion of */ - /* the LG instruction */ - /*-----------------------------------*/ - lkReg = code[5] & 0x0f; - - /*-----------------------------------*/ - /* The LG instruction has format: */ - /* E3x0ylllhh04 - where: */ - /* x = Rx; y = Ry; */ - /* lll = low 12 bits of displacement */ - /* hh = high 8 bits of displacement */ - /*-----------------------------------*/ - reg = code[0] >> 4; - displace = (code[2] << 12) + - ((code[0] & 0x0f) << 8) + - code[1]; - - if (reg > 5) - base = *((guchar **) (sp + S390_REG_SAVE_OFFSET + - sizeof(long)*(reg-6))); - else - base = *((guchar **) ((sp - CREATE_STACK_SIZE) + - CREATE_GR_OFFSET + - sizeof(long)*(reg-2))); - - /* Calls that need unboxing use R1 */ - if (lkReg == 1) { - if ((method->klass->valuetype) && - (!mono_aot_is_got_entry(code, base))) - addr = get_unbox_trampoline(method, addr); - - code = base + displace; - if (mono_domain_owns_vtable_slot(mono_domain_get(), - code)) - s390_patch_addr(code, addr); - } else { - code = base + displace; - s390_patch_addr(code, addr); - } - } - } + + opcode = *((unsigned short *) (orig_code - 6)); + if (opcode == 0xc0e5) { + /* This is the 'brasl' instruction */ + orig_code -= 4; + displace = ((gssize) addr - (gssize) (orig_code - 2)) / 2; + s390_patch_rel (orig_code, displace); + mono_arch_flush_icache (orig_code, 4); + } else { + /* This should be a 'lg %r14,4(%r13)' then a 'basr r14, r14' instruction */ + g_assert (orig_code [-8] == 0xe3); + g_assert (orig_code [-7] == 0xe0); + g_assert (orig_code [-6] == 0xd0); + g_assert (orig_code [-5] == 0x04); + g_assert (orig_code [-4] == 0x00); + g_assert (orig_code [-3] == 0x04); + opcode = *((unsigned short*) (orig_code - 2)); + g_assert (opcode == 0x0dee); + + /* The call address is stored in the 8 bytes preceeding the basr instruction */ + s390_patch_addr(orig_code - 16, (gssize)addr); + mono_arch_flush_icache (orig_code - 16, 8); } +} + +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - mono_arch_patch_plt_entry. */ +/* */ +/* Function - Patch a PLT entry - unused as yet. */ +/* */ +/*------------------------------------------------------------------*/ - return addr; +void +mono_arch_patch_plt_entry (guint8 *code, gpointer *got, mgreg_t *regs, guint8 *addr) +{ + g_assert_not_reached (); } /*========================= End of Function ========================*/ /*------------------------------------------------------------------*/ /* */ -/* Name - s390_class_init_trampoline */ +/* Name - mono_arch_nullify_class_init_trampoline */ /* */ -/* Function - Initialize a class and then no-op the call to */ -/* the trampoline. */ +/* Function - Nullify a call which calls a class init trampoline*/ /* */ /*------------------------------------------------------------------*/ -static void -s390_class_init_trampoline (void *vtable, guchar *code, char *sp) +void +mono_arch_nullify_class_init_trampoline (guint8 *code, mgreg_t *regs) { char patch[2] = {0x07, 0x00}; - mono_runtime_class_init (vtable); - code = code - 2; memcpy(code, patch, sizeof(patch)); @@ -263,7 +195,116 @@ s390_class_init_trampoline (void *vtable, guchar *code, char *sp) /*------------------------------------------------------------------*/ /* */ -/* Name - mono_arch_create_trampoline_code */ +/* Name - mono_arch_nullify_plt_entry */ +/* */ +/* Function - Nullify a PLT entry call. */ +/* */ +/*------------------------------------------------------------------*/ + +void +mono_arch_nullify_plt_entry (guint8 *code, mgreg_t *regs) +{ + g_assert_not_reached (); +} + +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - mono_arch_get_vcall_slot */ +/* */ +/* Function - This method is called by the arch independent */ +/* trampoline code to determine the vtable slot used by */ +/* the call which invoked the trampoline. */ +/* */ +/* Parameters - code - Pointer into caller code */ +/* regs - Register state at the point of the call */ +/* displacement - Out parameter which will receive */ +/* the displacement of the vtable slot */ +/* */ +/*------------------------------------------------------------------*/ + +gpointer +mono_arch_get_vcall_slot (guint8 *code, mgreg_t *regs, int *displacement) +{ + int reg, lkReg; + guchar* base; + unsigned short opcode; + char *sp; + MonoLMF *lmf = (MonoLMF *) ((gchar *) regs - sizeof(MonoLMF)); + + // We are passed sp instead of the register array +#if 0 + sp = (char *) regs; +#endif + sp = (char *) lmf->gregs[s390_r15]; + + *displacement = 0; + + opcode = *((unsigned short *) (code - 6)); + if (opcode == 0xc0e5) + /* This is the 'brasl' instruction */ + return NULL; + + /*-----------------------------------*/ + /* This is a basr r14,Rz instruction */ + /* If it's preceded by a LG Rx,d(Ry) */ + /* If Rz == 1 then this is virtual */ + /* call. */ + /*-----------------------------------*/ + code -= 6; + + /*-----------------------------------*/ + /* If call is preceded by LGR then */ + /* there's nothing to patch */ + /*-----------------------------------*/ + if ((code[0] == 0xb9) && (code[1] == 0x04)) + return NULL; + + /*-----------------------------------*/ + /* We back up until we're pointing at*/ + /* the base/displacement portion of */ + /* the LG instruction */ + /*-----------------------------------*/ + lkReg = code[5] & 0x0f; + + /*-----------------------------------*/ + /* The LG instruction has format: */ + /* E3x0ylllhh04 - where: */ + /* x = Rx; y = Ry; */ + /* lll = low 12 bits of displacement */ + /* hh = high 8 bits of displacement */ + /*-----------------------------------*/ + reg = code[0] >> 4; + *displacement = (code[2] << 12) | + ((code[0] & 0x0f) << 8) | + code[1]; + + if (code[2] & 0x80) + *displacement |= 0xfff00000; + + base = ((guchar *) lmf->gregs[reg]); +#if 0 + if (reg > 5) + base = *((guchar **) (sp + S390_REG_SAVE_OFFSET + + sizeof(long)*(reg-6))); + else + base = *((guchar **) ((sp - CREATE_STACK_SIZE) + + CREATE_GR_OFFSET + + sizeof(long)*(reg-2))); +#endif + if (lkReg != 1) + /* Non virtual call */ + return NULL; + + return base; +} + +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - mono_arch_create_trampoline_code */ /* */ /* Function - Create the designated type of trampoline according*/ /* to the 'tramp_type' parameter. */ @@ -274,377 +315,247 @@ guchar * mono_arch_create_trampoline_code (MonoTrampolineType tramp_type) { - guint8 *buf, *code = NULL; + guint8 *buf, *tramp, *code; int i, offset, lmfOffset; - if(!code) { - /* Now we'll create in 'buf' the S/390 trampoline code. This - is the trampoline code common to all methods */ + /* Now we'll create in 'buf' the S/390 trampoline code. This + is the trampoline code common to all methods */ - code = buf = mono_global_codeman_reserve(512); + code = buf = mono_global_codeman_reserve(512); - /*----------------------------------------------------------- - STEP 0: First create a non-standard function prologue with a - stack size big enough to save our registers. - -----------------------------------------------------------*/ + /*----------------------------------------------------------- + STEP 0: First create a non-standard function prologue with a + stack size big enough to save our registers. + -----------------------------------------------------------*/ - s390_stmg (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET); - s390_lgr (buf, s390_r11, s390_r15); - s390_aghi (buf, STK_BASE, -CREATE_STACK_SIZE); - s390_stg (buf, s390_r11, 0, STK_BASE, 0); - s390_stg (buf, s390_r1, 0, STK_BASE, METHOD_SAVE_OFFSET); - s390_stmg (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET); - - /* Save the FP registers */ - offset = CREATE_FP_OFFSET; - for (i = s390_f0; i <= s390_f15; ++i) { - s390_std (buf, i, 0, STK_BASE, offset); - 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 - 's390_magic_trampoline' and before the call to the native - method. - ----------------------------------------------------------*/ + s390_stmg (buf, s390_r6, s390_r15, STK_BASE, S390_REG_SAVE_OFFSET); + s390_lgr (buf, s390_r11, s390_r15); + s390_aghi (buf, STK_BASE, -CREATE_STACK_SIZE); + s390_stg (buf, s390_r11, 0, STK_BASE, 0); + s390_stg (buf, s390_r1, 0, STK_BASE, METHOD_SAVE_OFFSET); + s390_stmg (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET); + + /* Save the FP registers */ + offset = CREATE_FP_OFFSET; + for (i = s390_f0; i <= s390_f15; ++i) { + s390_std (buf, i, 0, STK_BASE, offset); + 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 + 's390_magic_trampoline' and before the call to the native + method. + ----------------------------------------------------------*/ - s390_basr (buf, s390_r13, 0); - s390_j (buf, 6); - s390_llong(buf, mono_get_lmf_addr); - s390_lg (buf, s390_r1, 0, s390_r13, 4); - s390_basr (buf, s390_r14, s390_r1); - - /*---------------------------------------------------------------*/ - /* we build the MonoLMF structure on the stack - see mini-s390.h */ - /* Keep in sync with the code in mono_arch_emit_prolog */ - /*---------------------------------------------------------------*/ - lmfOffset = CREATE_STACK_SIZE - sizeof(MonoLMF); + s390_basr (buf, s390_r13, 0); + s390_j (buf, 6); + s390_llong(buf, mono_get_lmf_addr); + s390_lg (buf, s390_r1, 0, s390_r13, 4); + s390_basr (buf, s390_r14, s390_r1); + + /*---------------------------------------------------------------*/ + /* we build the MonoLMF structure on the stack - see mini-s390.h */ + /* Keep in sync with the code in mono_arch_emit_prolog */ + /*---------------------------------------------------------------*/ + lmfOffset = CREATE_STACK_SIZE - sizeof(MonoLMF); - s390_lgr (buf, s390_r13, STK_BASE); - s390_aghi (buf, s390_r13, lmfOffset); + s390_lgr (buf, s390_r13, STK_BASE); + s390_aghi (buf, s390_r13, lmfOffset); - /*---------------------------------------------------------------*/ - /* Set lmf.lmf_addr = jit_tls->lmf */ - /*---------------------------------------------------------------*/ - s390_stg (buf, s390_r2, 0, s390_r13, + /*---------------------------------------------------------------*/ + /* Set lmf.lmf_addr = jit_tls->lmf */ + /*---------------------------------------------------------------*/ + s390_stg (buf, s390_r2, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, lmf_addr)); - /*---------------------------------------------------------------*/ - /* Get current lmf */ - /*---------------------------------------------------------------*/ - s390_lg (buf, s390_r0, 0, s390_r2, 0); + /*---------------------------------------------------------------*/ + /* Get current lmf */ + /*---------------------------------------------------------------*/ + s390_lg (buf, s390_r0, 0, s390_r2, 0); - /*---------------------------------------------------------------*/ - /* Set our lmf as the current lmf */ - /*---------------------------------------------------------------*/ - s390_stg (buf, s390_r13, 0, s390_r2, 0); + /*---------------------------------------------------------------*/ + /* Set our lmf as the current lmf */ + /*---------------------------------------------------------------*/ + s390_stg (buf, s390_r13, 0, s390_r2, 0); - /*---------------------------------------------------------------*/ - /* Have our lmf.previous_lmf point to the last lmf */ - /*---------------------------------------------------------------*/ - s390_stg (buf, s390_r0, 0, s390_r13, + /*---------------------------------------------------------------*/ + /* Have our lmf.previous_lmf point to the last lmf */ + /*---------------------------------------------------------------*/ + s390_stg (buf, s390_r0, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, previous_lmf)); - /*---------------------------------------------------------------*/ - /* save method info */ - /*---------------------------------------------------------------*/ - s390_lg (buf, s390_r1, 0, STK_BASE, METHOD_SAVE_OFFSET); - s390_stg (buf, s390_r1, 0, s390_r13, + /*---------------------------------------------------------------*/ + /* save method info */ + /*---------------------------------------------------------------*/ + s390_lg (buf, s390_r1, 0, STK_BASE, METHOD_SAVE_OFFSET); + s390_stg (buf, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, method)); - /*---------------------------------------------------------------*/ - /* save the current SP */ - /*---------------------------------------------------------------*/ - s390_lg (buf, s390_r1, 0, STK_BASE, 0); - s390_stg (buf, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, ebp)); + /*---------------------------------------------------------------*/ + /* save the current SP */ + /*---------------------------------------------------------------*/ + s390_lg (buf, s390_r1, 0, STK_BASE, 0); + s390_stg (buf, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, ebp)); - /*---------------------------------------------------------------*/ - /* save the current IP */ - /*---------------------------------------------------------------*/ - if (tramp_type == MONO_TRAMPOLINE_JUMP) { - s390_lghi (buf, s390_r1, 0); - } else { - s390_lg (buf, s390_r1, 0, s390_r1, S390_RET_ADDR_OFFSET); -// s390_la (buf, s390_r1, 0, s390_r1, 0); - } - s390_stg (buf, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, eip)); + /*---------------------------------------------------------------*/ + /* save the current IP */ + /*---------------------------------------------------------------*/ + if (tramp_type == MONO_TRAMPOLINE_JUMP) { + s390_lghi (buf, s390_r1, 0); + } else { + s390_lg (buf, s390_r1, 0, s390_r1, S390_RET_ADDR_OFFSET); + // s390_la (buf, s390_r1, 0, s390_r1, 0); + } + s390_stg (buf, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, eip)); - /*---------------------------------------------------------------*/ - /* Save general and floating point registers */ - /*---------------------------------------------------------------*/ - s390_stmg (buf, s390_r2, s390_r12, s390_r13, - G_STRUCT_OFFSET(MonoLMF, gregs[2])); - for (i = 0; i < 16; i++) { - s390_std (buf, i, 0, s390_r13, - G_STRUCT_OFFSET(MonoLMF, fregs[i])); - } - - /*---------------------------------------------------------------*/ - /* STEP 2: call 's390_magic_trampoline()', who will compile the */ - /* code and fix the method vtable entry for us */ - /*---------------------------------------------------------------*/ + /*---------------------------------------------------------------*/ + /* Save general and floating point registers */ + /*---------------------------------------------------------------*/ + s390_mvc (buf, 4*sizeof(gulong), s390_r13, G_STRUCT_OFFSET(MonoLMF, gregs[2]), + STK_BASE, CREATE_GR_OFFSET); + s390_mvc (buf, 10*sizeof(gulong), s390_r13, G_STRUCT_OFFSET(MonoLMF, gregs[6]), + s390_r11, S390_REG_SAVE_OFFSET); + + /* Simply copy fpregs already saved above */ + s390_mvc (buf, 16*sizeof(double), s390_r13, G_STRUCT_OFFSET(MonoLMF, fregs[0]), + STK_BASE, CREATE_FP_OFFSET); + + /*---------------------------------------------------------------*/ + /* STEP 2: call the C trampoline function */ + /*---------------------------------------------------------------*/ - /* Set arguments */ - - /* Arg 1: MonoMethod *method. It was put in r1 by the - method-specific trampoline code, and then saved before the call - to mono_get_lmf_addr()'. */ - s390_lg (buf, s390_r2, 0, STK_BASE, METHOD_SAVE_OFFSET); - - /* Arg 2: code (next address to the instruction that called us) */ - if (tramp_type == MONO_TRAMPOLINE_JUMP) { - s390_lghi (buf, s390_r3, 0); - } else { - s390_lg (buf, s390_r3, 0, s390_r11, S390_RET_ADDR_OFFSET); - } + /* Set arguments */ + + /* Arg 1: mgreg_t *regs. We pass sp instead */ + s390_la (buf, s390_r2, 0, STK_BASE, CREATE_STACK_SIZE); - /* Arg 3: stack pointer */ - s390_lgr (buf, s390_r4, STK_BASE); - s390_ahi (buf, s390_r4, CREATE_STACK_SIZE); + /* Arg 2: code (next address to the instruction that called us) */ + if (tramp_type == MONO_TRAMPOLINE_JUMP) { + s390_lghi (buf, s390_r3, 0); + } else { + s390_lg (buf, s390_r3, 0, s390_r11, S390_RET_ADDR_OFFSET); + } + + /* Arg 3: MonoMethod *method. It was put in r1 by the + method-specific trampoline code, and then saved before the call + to mono_get_lmf_addr()'. */ + s390_lg (buf, s390_r4, 0, STK_BASE, METHOD_SAVE_OFFSET); + + /* Arg 4: trampoline address. Ignore for now */ - /* Calculate call address and call - 's390_magic_trampoline'. Return value will be in r2 */ - s390_basr (buf, s390_r13, 0); - s390_j (buf, 6); - if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT) { - s390_llong(buf, s390_class_init_trampoline); - } else { - s390_llong(buf, s390_magic_trampoline); - } - s390_lg (buf, s390_r1, 0, s390_r13, 4); - s390_basr (buf, s390_r14, s390_r1); + /* Calculate call address and call the C trampoline. Return value will be in r2 */ + s390_basr (buf, s390_r13, 0); + s390_j (buf, 6); + tramp = (guint8*)mono_get_trampoline_func (tramp_type); + s390_llong (buf, tramp); + s390_lg (buf, s390_r1, 0, s390_r13, 4); + s390_basr (buf, s390_r14, s390_r1); - /* OK, code address is now on r2. Move it to r1, so that we - can restore r2 and use it from r1 later */ - s390_lgr (buf, s390_r1, s390_r2); - - /*---------------------------------------------------------- - STEP 3: Restore the LMF - ----------------------------------------------------------*/ - restoreLMF(buf, STK_BASE, CREATE_STACK_SIZE); + /* OK, code address is now on r2. Move it to r1, so that we + can restore r2 and use it from r1 later */ + s390_lgr (buf, s390_r1, s390_r2); + + /*---------------------------------------------------------- + STEP 3: Restore the LMF + ----------------------------------------------------------*/ + restoreLMF(buf, STK_BASE, CREATE_STACK_SIZE); - /*---------------------------------------------------------- - STEP 4: call the compiled method - ----------------------------------------------------------*/ + /*---------------------------------------------------------- + STEP 4: call the compiled method + ----------------------------------------------------------*/ - /* Restore registers */ + /* Restore registers */ - s390_lmg (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET); + s390_lmg (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET); - /* Restore the FP registers */ - offset = CREATE_FP_OFFSET; - for (i = s390_f0; i <= s390_f15; ++i) { - s390_ld (buf, i, 0, STK_BASE, offset); - offset += 8; - } - - /* Restore stack pointer and jump to the code - - R14 contains the return address to our caller */ - s390_lgr (buf, STK_BASE, s390_r11); - s390_lmg (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET); - s390_br (buf, s390_r1); - - /* Flush instruction cache, since we've generated code */ - mono_arch_flush_icache (code, buf - code); - - /* Sanity check */ - g_assert ((buf - code) <= 512); + /* Restore the FP registers */ + offset = CREATE_FP_OFFSET; + for (i = s390_f0; i <= s390_f15; ++i) { + s390_ld (buf, i, 0, STK_BASE, offset); + offset += 8; } - return code; -} - -/*========================= End of Function ========================*/ - -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_create_jump_trampoline */ -/* */ -/* Function - Create the designated type of trampoline according*/ -/* to the 'tramp_type' parameter. */ -/* */ -/*------------------------------------------------------------------*/ - -MonoJitInfo * -mono_arch_create_jump_trampoline (MonoMethod *method) -{ - guint8 *code, *buf, *tramp = NULL; - MonoJitInfo *ji; - MonoDomain *domain = mono_domain_get(); - gint32 displace; - - tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_JUMP); - - mono_domain_lock (domain); - code = buf = mono_code_manager_reserve (domain->code_mp, JUMP_TRAMPOLINE_SIZE); - mono_domain_unlock (domain); - - s390_basr (buf, s390_r1, 0); - s390_j (buf, 6); - s390_llong(buf, method); - s390_lg (buf, s390_r1, 0, s390_r1, 4); - displace = (tramp - buf) / 2; - s390_jcl (buf, S390_CC_UN, displace); + /* Restore stack pointer and jump to the code - + R14 contains the return address to our caller */ + s390_lgr (buf, STK_BASE, s390_r11); + s390_lmg (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET); - mono_arch_flush_icache (code, buf-code); + if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT || tramp_type == MONO_TRAMPOLINE_GENERIC_CLASS_INIT) + s390_br (buf, s390_r14); + else + s390_br (buf, s390_r1); - g_assert ((buf - code) <= JUMP_TRAMPOLINE_SIZE); - - ji = g_new0 (MonoJitInfo, 1); - ji->method = method; - ji->code_start = code; - ji->code_size = buf - code; + /* Flush instruction cache, since we've generated code */ + mono_arch_flush_icache (code, buf - code); - mono_jit_stats.method_trampolines++; + /* Sanity check */ + g_assert ((buf - code) <= 512); - return ji; + return code; } /*========================= End of Function ========================*/ /*------------------------------------------------------------------*/ /* */ -/* Name - mono_arch_create_jit_trampoline */ -/* */ -/* Function - Creates a trampoline function for virtual methods.*/ -/* If the created code is called it first starts JIT */ -/* compilation and then calls the newly created */ -/* method. It also replaces the corresponding vtable */ -/* entry (see s390_magic_trampoline). */ +/* Name - mono_arch_create_specific_trampoline */ /* */ -/* A trampoline consists of two parts: a main */ -/* fragment, shared by all method trampolines, and */ -/* and some code specific to each method, which */ -/* hard-codes a reference to that method and then */ -/* calls the main fragment. */ -/* */ -/* The main fragment contains a call to */ -/* 's390_magic_trampoline', which performs a call */ -/* to the JIT compiler and substitutes the method- */ -/* specific fragment with some code that directly */ -/* calls the JIT-compiled method. */ -/* */ -/* Parameter - method - Pointer to the method information */ -/* */ -/* Returns - A pointer to the newly created code */ +/* Function - Creates the given kind of specific trampoline */ /* */ /*------------------------------------------------------------------*/ gpointer -mono_arch_create_jit_trampoline (MonoMethod *method) +mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len) { - guint8 *code, *buf; - static guint8 *vc = NULL; + guint8 *code, *buf, *tramp; gint32 displace; - vc = mono_get_trampoline_code (MONO_TRAMPOLINE_GENERIC); + tramp = mono_get_trampoline_code (tramp_type); - /* 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 r1 to keep that value, for instance. */ - code = buf = mono_global_codeman_reserve(METHOD_TRAMPOLINE_SIZE); + /*----------------------------------------------------------*/ + /* 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 r1 to keep it. */ + /*----------------------------------------------------------*/ + code = buf = mono_domain_code_reserve (domain, SPECIFIC_TRAMPOLINE_SIZE); s390_basr (buf, s390_r1, 0); s390_j (buf, 6); - s390_llong(buf, method); + s390_llong(buf, arg1); s390_lg (buf, s390_r1, 0, s390_r1, 4); - displace = (vc - buf) / 2; + displace = (tramp - buf) / 2; s390_jcl (buf, S390_CC_UN, displace); /* Flush instruction cache, since we've generated code */ mono_arch_flush_icache (code, buf - code); - - /* Sanity check */ - g_assert ((buf - code) <= METHOD_TRAMPOLINE_SIZE); - - return code; -} - -/*========================= End of Function ========================*/ - -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_create_class_init_trampoline */ -/* */ -/* Function - Creates a trampoline function to run a type init- */ -/* ializer. If the trampoline is called, it calls */ -/* mono_runtime_class_init with the given vtable, */ -/* then patches the caller code so it does not get */ -/* called any more. */ -/* */ -/* Parameter - vtable - The type to initialize */ -/* */ -/* Returns - A pointer to the newly created code */ -/* */ -/*------------------------------------------------------------------*/ - -gpointer -mono_arch_create_class_init_trampoline (MonoVTable *vtable) -{ - guint8 *code, *buf, *tramp; - 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. */ - /*-----------------------------------------------------------*/ - code = buf = mono_global_codeman_reserve(METHOD_TRAMPOLINE_SIZE); - - s390_stg (buf, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET); - s390_aghi (buf, STK_BASE, -S390_MINIMAL_STACK_SIZE); - - s390_basr (buf, s390_r1, 0); - s390_j (buf, 10); - s390_llong(buf, vtable); - s390_llong(buf, s390_class_init_trampoline); - s390_lgr (buf, s390_r3, s390_r14); - s390_lg (buf, s390_r2, 0, s390_r1, 4); - s390_lghi (buf, s390_r4, 0); - s390_lg (buf, s390_r1, 0, s390_r1, 12); - s390_basr (buf, s390_r14, s390_r1); - - s390_aghi (buf, STK_BASE, S390_MINIMAL_STACK_SIZE); - s390_lg (buf, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET); - s390_br (buf, s390_r14); - - /* Flush instruction cache, since we've generated code */ - mono_arch_flush_icache (code, buf - code); - /* Sanity check */ - g_assert ((buf - code) <= METHOD_TRAMPOLINE_SIZE); - - mono_jit_stats.method_trampolines++; + g_assert ((buf - code) <= SPECIFIC_TRAMPOLINE_SIZE); + if (code_len) + *code_len = buf - code; + return code; -} +} /*========================= End of Function ========================*/ /*------------------------------------------------------------------*/ /* */ -/* Name - mono_debuger_create_notification_function */ +/* Name - mono_arch_create_rgctx_lazy_fetch_trampoline */ /* */ -/* Function - This method is only called when running in the */ -/* Mono debugger. It returns a pointer to the */ -/* arch specific notification function. */ +/* Function - */ /* */ /*------------------------------------------------------------------*/ gpointer -mono_debugger_create_notification_function (gpointer *notification_address) +mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 encoded_offset) { - guint8 *ptr, *buf; - - ptr = buf = mono_global_codeman_reserve (16); - s390_break (buf); - if (notification_address) - *notification_address = buf; - s390_br (buf, s390_r14); - - return ptr; -} + /* FIXME: implement! */ + g_assert_not_reached (); + return NULL; +} /*========================= End of Function ========================*/