X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Ftramp-s390x.c;h=8f2875afdff874cb0cf258b322d5061f3b3087d5;hb=1dbd5e22fa7f7922ffc448a10bee2fb219fca154;hp=cf442e374307b80150bd32b83ef069b3f7e18afa;hpb=af90548a08ef5effc93b083b7eec44daa178b141;p=mono.git diff --git a/mono/mini/tramp-s390x.c b/mono/mini/tramp-s390x.c index cf442e37430..8f2875afdff 100644 --- a/mono/mini/tramp-s390x.c +++ b/mono/mini/tramp-s390x.c @@ -1,6 +1,6 @@ /*------------------------------------------------------------------*/ /* */ -/* Name - tramp-s390.c */ +/* Name - tramp-s390x.c */ /* */ /* Function - JIT trampoline code for S/390. */ /* */ @@ -27,12 +27,14 @@ #define CREATE_FP_OFFSET CREATE_GR_OFFSET+GR_SAVE_SIZE #define CREATE_LMF_OFFSET CREATE_FP_OFFSET+FP_SAVE_SIZE #define CREATE_STACK_SIZE (CREATE_LMF_OFFSET+2*sizeof(long)+sizeof(MonoLMF)) +#define GENERIC_REG_OFFSET CREATE_STACK_SIZE + \ + S390_REG_SAVE_OFFSET + \ + 3*sizeof(long) /*------------------------------------------------------------------*/ /* Method-specific trampoline code fragment sizes */ /*------------------------------------------------------------------*/ -#define METHOD_TRAMPOLINE_SIZE 96 -#define JUMP_TRAMPOLINE_SIZE 96 +#define SPECIFIC_TRAMPOLINE_SIZE 96 /*========================= End of Defines =========================*/ @@ -75,7 +77,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. */ @@ -88,18 +90,14 @@ /* */ /*------------------------------------------------------------------*/ -static gpointer -get_unbox_trampoline (MonoMethod *method, gpointer addr) +gpointer +mono_arch_get_unbox_trampoline (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))) - 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); @@ -110,6 +108,8 @@ get_unbox_trampoline (MonoMethod *method, gpointer addr) g_assert ((code - start) <= 28); + mono_arch_flush_icache (start, code - start); + return start; } @@ -117,142 +117,73 @@ get_unbox_trampoline (MonoMethod *method, gpointer addr) /*------------------------------------------------------------------*/ /* */ -/* Name - s390_magic_trampoline */ +/* Name - mono_arch_patch_callsite */ /* */ -/* 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 */ -/* */ -/* 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 ========================*/ - return addr; +/*------------------------------------------------------------------*/ +/* */ +/* Name - mono_arch_patch_plt_entry. */ +/* */ +/* Function - Patch a PLT entry - unused as yet. */ +/* */ +/*------------------------------------------------------------------*/ + +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)); @@ -262,195 +193,234 @@ s390_class_init_trampoline (void *vtable, guchar *code, char *sp) /*------------------------------------------------------------------*/ /* */ -/* Name - mono_arch_create_trampoline_code */ +/* Name - mono_arch_get_nullified_class_init */ +/* */ +/* Function - Nullify a PLT entry call. */ +/* */ +/*------------------------------------------------------------------*/ + +gpointer +mono_arch_get_nullified_class_init_trampoline (MonoTrampInfo **info) +{ + guint8 *buf, *code; + + code = buf = mono_global_codeman_reserve (16); + + s390_br (code, s390_r14); + + if (info) + *info = mono_tramp_info_create ("nullified_class_init_trampoline", + buf, code - buf, NULL, NULL); + + return (buf); +} + +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - mono_arch_create_trampoline_code */ /* */ /* Function - Create the designated type of trampoline according*/ /* to the 'tramp_type' parameter. */ /* */ /*------------------------------------------------------------------*/ -guchar * -mono_arch_create_trampoline_code (MonoTrampolineType tramp_type) +guchar* +mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInfo **info, gboolean aot) { - - guint8 *buf, *code = NULL; + char *tramp_name; + guint8 *buf, *tramp, *code; int i, offset, lmfOffset; + GSList *unwind_ops = NULL; + MonoJumpInfo *ji = NULL; - if(!code) { - /* Now we'll create in 'buf' the S/390 trampoline code. This - is the trampoline code common to all methods */ + g_assert (!aot); + + /* 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: Trampoline argument */ + if (tramp_type == MONO_TRAMPOLINE_GENERIC_CLASS_INIT) + s390_lg (buf, s390_r4, 0, STK_BASE, GENERIC_REG_OFFSET); + else + 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); + /* 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); + + if (MONO_TRAMPOLINE_TYPE_MUST_RETURN(tramp_type)) { + s390_lgr (buf, s390_r2, s390_r1); + s390_br (buf, s390_r14); + } else { + 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); + if (info) { + tramp_name = mono_get_generic_trampoline_name (tramp_type); + *info = mono_tramp_info_create (tramp_name, buf, buf - code, ji, unwind_ops); + g_free (tramp_name); } + /* Sanity check */ + g_assert ((buf - code) <= 512); + return code; } @@ -458,190 +428,257 @@ mono_arch_create_trampoline_code (MonoTrampolineType tramp_type) /*------------------------------------------------------------------*/ /* */ -/* Name - mono_arch_create_jump_trampoline */ +/* Name - mono_arch_create_specific_trampoline */ /* */ -/* Function - Create the designated type of trampoline according*/ -/* to the 'tramp_type' parameter. */ +/* Function - Creates the given kind of specific trampoline */ /* */ /*------------------------------------------------------------------*/ -MonoJitInfo * -mono_arch_create_jump_trampoline (MonoMethod *method) +gpointer +mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len) { - guint8 *code, *buf, *tramp = NULL; - MonoJitInfo *ji; - MonoDomain *domain = mono_domain_get(); + guint8 *code, *buf, *tramp; gint32 displace; - tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_JUMP); + tramp = mono_get_trampoline_code (tramp_type); - mono_domain_lock (domain); - code = buf = mono_code_manager_reserve (domain->code_mp, JUMP_TRAMPOLINE_SIZE); - mono_domain_unlock (domain); + /*----------------------------------------------------------*/ + /* 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 = (tramp - buf) / 2; - s390_jcl (buf, S390_CC_UN, displace); + s390_jg (buf, displace); - mono_arch_flush_icache (code, buf-code); + /* Flush instruction cache, since we've generated code */ + mono_arch_flush_icache (code, buf - code); - g_assert ((buf - code) <= JUMP_TRAMPOLINE_SIZE); - - ji = g_new0 (MonoJitInfo, 1); - ji->method = method; - ji->code_start = code; - ji->code_size = buf - code; - - mono_jit_stats.method_trampolines++; + /* Sanity check */ + g_assert ((buf - code) <= SPECIFIC_TRAMPOLINE_SIZE); - return ji; -} + if (code_len) + *code_len = buf - code; + + return code; +} /*========================= End of Function ========================*/ /*------------------------------------------------------------------*/ /* */ -/* Name - mono_arch_create_jit_trampoline */ +/* Name - mono_arch_create_rgctx_lazy_fetch_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). */ -/* */ -/* 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 - */ /* */ /*------------------------------------------------------------------*/ gpointer -mono_arch_create_jit_trampoline (MonoMethod *method) +mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info, gboolean aot) { +#ifdef MONO_ARCH_VTABLE_REG + guint8 *tramp; guint8 *code, *buf; - static guint8 *vc = NULL; + guint8 **rgctx_null_jumps; gint32 displace; + int tramp_size, + depth, + index, + iPatch = 0, + i; + gboolean mrgctx; + MonoJumpInfo *ji = NULL; + GSList *unwind_ops = NULL; + + mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot); + index = MONO_RGCTX_SLOT_INDEX (slot); + if (mrgctx) + index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer); + for (depth = 0; ; ++depth) { + int size = mono_class_rgctx_get_array_size (depth, mrgctx); + + if (index < size - 1) + break; + index -= size - 1; + } - vc = mono_get_trampoline_code (MONO_TRAMPOLINE_GENERIC); + tramp_size = 48 + 16 * depth; + if (mrgctx) + tramp_size += 4; + else + tramp_size += 12; + + code = buf = mono_global_codeman_reserve (tramp_size); + + unwind_ops = mono_arch_get_cie_program (); + + rgctx_null_jumps = g_malloc (sizeof (guint8*) * (depth + 2)); + + if (mrgctx) { + /* get mrgctx ptr */ + s390_lgr (code, s390_r1, s390_r2); + } else { + /* load rgctx ptr from vtable */ + s390_lg (code, s390_r1, 0, s390_r2, G_STRUCT_OFFSET(MonoVTable, runtime_generic_context)); + /* is the rgctx ptr null? */ + s390_ltgr (code, s390_r1, s390_r1); + /* if yes, jump to actual trampoline */ + rgctx_null_jumps [iPatch++] = code; + s390_jge (code, 0); + } - /* 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); + for (i = 0; i < depth; ++i) { + /* load ptr to next array */ + if (mrgctx && i == 0) + s390_lg (code, s390_r1, 0, s390_r1, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT); + else + s390_lg (code, s390_r1, 0, s390_r1, 0); + s390_ltgr (code, s390_r1, s390_r1); + /* if the ptr is null then jump to actual trampoline */ + rgctx_null_jumps [iPatch++] = code; + s390_jge (code, 0); + } - s390_basr (buf, s390_r1, 0); - s390_j (buf, 6); - s390_llong(buf, method); - s390_lg (buf, s390_r1, 0, s390_r1, 4); - displace = (vc - buf) / 2; - s390_jcl (buf, S390_CC_UN, displace); + /* fetch slot */ + s390_lg (code, s390_r1, 0, s390_r1, (sizeof (gpointer) * (index + 1))); + /* is the slot null? */ + s390_ltgr (code, s390_r1, s390_r1); + /* if yes, jump to actual trampoline */ + rgctx_null_jumps [iPatch++] = code; + s390_jge (code, 0); + /* otherwise return r1 */ + s390_lgr (code, s390_r2, s390_r1); + s390_br (code, s390_r14); + + for (i = 0; i < iPatch; i++) { + displace = ((uintptr_t) code - (uintptr_t) rgctx_null_jumps[i]) / 2; + s390_patch_rel ((rgctx_null_jumps [i] + 2), 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; -} + g_free (rgctx_null_jumps); + + /* move the rgctx pointer to the VTABLE register */ + s390_lgr (code, MONO_ARCH_VTABLE_REG, s390_r2); + + tramp = mono_arch_create_specific_trampoline (GUINT_TO_POINTER (slot), + MONO_TRAMPOLINE_RGCTX_LAZY_FETCH, mono_get_root_domain (), NULL); + + /* jump to the actual trampoline */ + displace = (tramp - code) / 2; + s390_jg (code, displace); + + mono_arch_flush_icache (buf, code - buf); + + g_assert (code - buf <= tramp_size); + + if (info) { + char *name = mono_get_rgctx_fetch_trampoline_name (slot); + *info = mono_tramp_info_create (name, buf, code - buf, ji, unwind_ops); + g_free (name); + } + + return(buf); +#else + g_assert_not_reached (); +#endif + return(NULL); +} /*========================= 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. */ +/* Name - mono_arch_get_static_rgctx_trampoline */ /* */ -/* Parameter - vtable - The type to initialize */ -/* */ -/* Returns - A pointer to the newly created code */ +/* Function - Create a trampoline which sets RGCTX_REG to MRGCTX*/ +/* then jumps to ADDR. */ /* */ /*------------------------------------------------------------------*/ gpointer -mono_arch_create_class_init_trampoline (MonoVTable *vtable) +mono_arch_get_static_rgctx_trampoline (MonoMethod *m, + MonoMethodRuntimeGenericContext *mrgctx, + gpointer addr) { - 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); + guint8 *code, *start; + gint32 displace; + int buf_len; - s390_stg (buf, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET); - s390_aghi (buf, STK_BASE, -S390_MINIMAL_STACK_SIZE); + MonoDomain *domain = mono_domain_get (); - 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); + buf_len = 32; - 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); + start = code = mono_domain_code_reserve (domain, buf_len); - /* Flush instruction cache, since we've generated code */ - mono_arch_flush_icache (code, buf - code); - - /* Sanity check */ - g_assert ((buf - code) <= METHOD_TRAMPOLINE_SIZE); + s390_basr (code, s390_r1, 0); + s390_j (code, 6); + s390_llong(code, mrgctx); + s390_lg (code, MONO_ARCH_RGCTX_REG, 0, s390_r1, 4); + displace = ((uintptr_t) addr - (uintptr_t) code) / 2; + s390_jg (code, displace); + g_assert ((code - start) < buf_len); - mono_jit_stats.method_trampolines++; + mono_arch_flush_icache (start, code - start); - return code; -} + return(start); +} /*========================= End of Function ========================*/ /*------------------------------------------------------------------*/ /* */ -/* Name - mono_debuger_create_notification_function */ +/* Name - mono_arch_create_generic_class_init_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 (MonoCodeManager *codeman) +mono_arch_create_generic_class_init_trampoline (MonoTrampInfo **info, gboolean aot) { - guint8 *ptr, *buf; + guint8 *tramp; + guint8 *code, *buf; + static int byte_offset = -1; + static guint8 bitmask; + guint8 *jump; + gint32 displace; + int tramp_size; + GSList *unwind_ops = NULL; + MonoJumpInfo *ji = NULL; + + tramp_size = 48; + + code = buf = mono_global_codeman_reserve (tramp_size); + + unwind_ops = mono_arch_get_cie_program (); + + if (byte_offset < 0) + mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask); + + s390_llgc(code, s390_r0, 0, MONO_ARCH_VTABLE_REG, byte_offset); + s390_nill(code, s390_r0, bitmask); + s390_bnzr(code, s390_r14); + + tramp = mono_arch_create_specific_trampoline (NULL, MONO_TRAMPOLINE_GENERIC_CLASS_INIT, + mono_get_root_domain (), NULL); + + /* jump to the actual trampoline */ + displace = (tramp - code) / 2; + s390_jg (code, displace); + + mono_arch_flush_icache (buf, code - buf); + + g_assert (code - buf <= tramp_size); - ptr = buf = mono_code_manager_reserve (codeman, 16); - s390_break (buf); - s390_br (buf, s390_r14); + if (info) + *info = mono_tramp_info_create ("generic_class_init_trampoline", buf, code - buf, ji, unwind_ops); - return ptr; + return(buf); } /*========================= End of Function ========================*/