X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Ftramp-s390x.c;h=e6bbe8ccb7eea82ff0a57b974d5da42086ef6408;hb=5bde5effed9f0e7dd3279f62c56bb488ff11b4ce;hp=399ce487dfd37fa4181226365f3e4acc86b26dcc;hpb=95149da03ea22c4e6f7e9feda77ea2808fbf6586;p=mono.git diff --git a/mono/mini/tramp-s390x.c b/mono/mini/tramp-s390x.c index 399ce487dfd..e6bbe8ccb7e 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,6 +27,9 @@ #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 */ @@ -43,13 +46,16 @@ #include #include +#include #include #include #include +#include #include #include "mini.h" #include "mini-s390x.h" +#include "support-s390x.h" /*========================= End of Includes ========================*/ @@ -82,14 +88,13 @@ /* When value type methods are called through the */ /* vtable we need to unbox the 'this' argument. */ /* */ -/* Parameters - gsctx - Generic sharing context */ -/* method - Methd pointer */ +/* Parameters - method - Methd pointer */ /* addr - Pointer to native code for method */ /* */ /*------------------------------------------------------------------*/ gpointer -mono_arch_get_unbox_trampoline (MonoGenericSharingContext *gsctx, MonoMethod *method, gpointer addr) +mono_arch_get_unbox_trampoline (MonoMethod *method, gpointer addr) { guint8 *code, *start; int this_pos = s390_r2; @@ -97,16 +102,14 @@ mono_arch_get_unbox_trampoline (MonoGenericSharingContext *gsctx, MonoMethod *me start = code = mono_domain_code_reserve (domain, 28); - s390_basr (code, s390_r1, 0); - s390_j (code, 6); - s390_llong(code, addr); - s390_lg (code, s390_r1, 0, s390_r1, 4); + S390_SET (code, s390_r1, addr); s390_aghi (code, this_pos, sizeof(MonoObject)); s390_br (code, s390_r1); g_assert ((code - start) <= 28); mono_arch_flush_icache (start, code - start); + mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_UNBOX_TRAMPOLINE, method); return start; } @@ -127,27 +130,17 @@ mono_arch_patch_callsite (guint8 *method_start, guint8 *orig_code, guint8 *addr) gint32 displace; unsigned short opcode; - opcode = *((unsigned short *) (orig_code - 6)); - if (opcode == 0xc0e5) { + opcode = *((unsigned short *) (orig_code - 2)); + if (opcode == 0x0dee) { + /* This should be a 'iihf/iilf' sequence */ + S390_EMIT_CALL((orig_code - 14), addr); + mono_arch_flush_icache (orig_code - 14, 12); + } else { /* 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); } } @@ -191,41 +184,29 @@ mono_arch_nullify_class_init_trampoline (guint8 *code, mgreg_t *regs) /*------------------------------------------------------------------*/ /* */ -/* Name - mono_arch_nullify_plt_entry */ +/* Name - mono_arch_get_nullified_class_init */ /* */ /* Function - Nullify a PLT entry call. */ /* */ /*------------------------------------------------------------------*/ -void -mono_arch_nullify_plt_entry (guint8 *code, mgreg_t *regs) +gpointer +mono_arch_get_nullified_class_init_trampoline (MonoTrampInfo **info) { - g_assert_not_reached (); -} + guint8 *buf, *code; -/*========================= End of Function ========================*/ + code = buf = mono_global_codeman_reserve (16); -/*------------------------------------------------------------------*/ -/* */ -/* 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 */ -/* */ -/*------------------------------------------------------------------*/ + s390_br (code, s390_r14); -gpointer -mono_arch_get_vcall_slot (guint8 *code, mgreg_t *regs, int *displacement) -{ - /* Not used on s390x */ - g_assert_not_reached (); - return NULL; + mono_arch_flush_icache (buf, code - buf); + mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL); + + if (info) + *info = mono_tramp_info_create ("nullified_class_init_trampoline", + buf, code - buf, NULL, NULL); + + return (buf); } /*========================= End of Function ========================*/ @@ -242,18 +223,25 @@ mono_arch_get_vcall_slot (guint8 *code, mgreg_t *regs, int *displacement) guchar* mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInfo **info, gboolean aot) { + char *tramp_name; guint8 *buf, *tramp, *code; - int i, offset, lmfOffset; + int i, offset, lmfOffset, has_caller; + GSList *unwind_ops = NULL; + MonoJumpInfo *ji = NULL; g_assert (!aot); - if (info) - *info = NULL; /* 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); + if ((tramp_type == MONO_TRAMPOLINE_JUMP) || + (tramp_type == MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD)) + has_caller = 0; + else + has_caller = 1; + /*----------------------------------------------------------- STEP 0: First create a non-standard function prologue with a stack size big enough to save our registers. @@ -280,10 +268,7 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf 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_SET (buf, s390_r1, mono_get_lmf_addr); s390_basr (buf, s390_r14, s390_r1); /*---------------------------------------------------------------*/ @@ -333,11 +318,10 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf /*---------------------------------------------------------------*/ /* save the current IP */ /*---------------------------------------------------------------*/ - if (tramp_type == MONO_TRAMPOLINE_JUMP) { - s390_lghi (buf, s390_r1, 0); - } else { + if (has_caller) { s390_lg (buf, s390_r1, 0, s390_r1, S390_RET_ADDR_OFFSET); - // s390_la (buf, s390_r1, 0, s390_r1, 0); + } else { + s390_lghi (buf, s390_r1, 0); } s390_stg (buf, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, eip)); @@ -363,25 +347,23 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf s390_la (buf, s390_r2, 0, STK_BASE, 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 { + if (has_caller) { s390_lg (buf, s390_r3, 0, s390_r11, S390_RET_ADDR_OFFSET); + } else { + s390_lghi (buf, s390_r3, 0); } - /* 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 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 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_SET (buf, s390_r1, tramp); s390_basr (buf, s390_r14, s390_r1); /* OK, code address is now on r2. Move it to r1, so that we @@ -413,14 +395,23 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf s390_lgr (buf, STK_BASE, s390_r11); s390_lmg (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET); - 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); + 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); + mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL); + 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); @@ -429,6 +420,28 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf /*========================= End of Function ========================*/ +/*------------------------------------------------------------------*/ +/* */ +/* Name - mono_arch_invalidate_method */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + +void +mono_arch_invalidate_method (MonoJitInfo *ji, void *func, gpointer func_arg) +{ + /* FIXME: This is not thread safe */ + guint8 *code = ji->code_start; + + S390_SET (code, s390_r1, func); + S390_SET (code, s390_r2, func_arg); + s390_br (code, s390_r1); + +} + +/*========================= End of Function ========================*/ + /*------------------------------------------------------------------*/ /* */ /* Name - mono_arch_create_specific_trampoline */ @@ -452,15 +465,14 @@ mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_ty /*----------------------------------------------------------*/ code = buf = mono_domain_code_reserve (domain, SPECIFIC_TRAMPOLINE_SIZE); - s390_basr (buf, s390_r1, 0); - s390_j (buf, 6); - s390_llong(buf, arg1); - s390_lg (buf, s390_r1, 0, s390_r1, 4); + S390_SET (buf, s390_r1, arg1); displace = (tramp - buf) / 2; - s390_jcl (buf, S390_CC_UN, displace); + s390_jg (buf, displace); /* Flush instruction cache, since we've generated code */ mono_arch_flush_icache (code, buf - code); + mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE, + (void *) mono_get_generic_trampoline_simple_name (tramp_type)); /* Sanity check */ g_assert ((buf - code) <= SPECIFIC_TRAMPOLINE_SIZE); @@ -484,9 +496,277 @@ mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_ty gpointer mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info, gboolean aot) { - /* FIXME: implement! */ +#ifdef MONO_ARCH_VTABLE_REG + guint8 *tramp; + guint8 *code, *buf; + 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; + } + + 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, MONO_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); + } + + 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); + } + + /* 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); + } + + 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); + mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL); + + 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 (); - return NULL; +#endif + return(NULL); } /*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - mono_arch_get_static_rgctx_trampoline */ +/* */ +/* Function - Create a trampoline which sets RGCTX_REG to MRGCTX*/ +/* then jumps to ADDR. */ +/* */ +/*------------------------------------------------------------------*/ + +gpointer +mono_arch_get_static_rgctx_trampoline (MonoMethod *m, + MonoMethodRuntimeGenericContext *mrgctx, + gpointer addr) +{ + guint8 *code, *start; + gint32 displace; + int buf_len; + + MonoDomain *domain = mono_domain_get (); + + buf_len = 32; + + start = code = mono_domain_code_reserve (domain, buf_len); + + S390_SET (code, MONO_ARCH_RGCTX_REG, mrgctx); + displace = ((uintptr_t) addr - (uintptr_t) code) / 2; + s390_jg (code, displace); + g_assert ((code - start) < buf_len); + + mono_arch_flush_icache (start, code - start); + mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_HELPER, NULL); + + return(start); +} + +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - handler_block_trampoline_helper */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + +static void +handler_block_trampoline_helper (gpointer *ptr) +{ + MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id); + *ptr = jit_tls->handler_block_return_address; +} + +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - mono_arch_create_handler_block_trampoline */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + +gpointer +mono_arch_create_handler_block_trampoline (MonoTrampInfo **info, gboolean aot) +{ + guint8 *tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD); + guint8 *code, *buf; + int tramp_size = 64; + MonoJumpInfo *ji = NULL; + GSList *unwind_ops = NULL; + + g_assert (!aot); + + code = buf = mono_global_codeman_reserve (tramp_size); + + /* + * This trampoline restore the call chain of the handler block + * then jumps into the code that deals with it. + */ + + if (mono_get_jit_tls_offset () != -1) { + s390_ear (code, s390_r1, 0); + s390_sllg (code, s390_r1, s390_r1, 0, 32); + s390_ear (code, s390_r1, 1); + S390_SET (code, s390_r14, mono_get_jit_tls_offset()); + s390_lg (code, s390_r14, s390_r1, 0, G_STRUCT_OFFSET(MonoJitTlsData, handler_block_return_address)); + /* + * Simulate a call + */ + S390_SET (code, s390_r1, tramp); + s390_br (code, s390_r1); + } else { + /* + * Slow path uses a C helper + */ + S390_SET (code, s390_r2, tramp); + S390_SET (code, s390_r1, handler_block_trampoline_helper); + s390_br (code, s390_r1); + } + + mono_arch_flush_icache (buf, code - buf); + mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL); + g_assert (code - buf <= tramp_size); + + if (info) + *info = mono_tramp_info_create ("handler_block_trampoline", buf, code - buf, ji, unwind_ops); + + return buf; +} + +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - mono_arch_create_generic_class_init_trampoline */ +/* */ +/* Function - */ +/* */ +/*------------------------------------------------------------------*/ + +gpointer +mono_arch_create_generic_class_init_trampoline (MonoTrampInfo **info, gboolean aot) +{ + guint8 *tramp; + guint8 *code, *buf; + static int byte_offset = -1; + static guint8 bitmask; + 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); + + if (info) + *info = mono_tramp_info_create ("generic_class_init_trampoline", buf, code - buf, ji, unwind_ops); + + return(buf); +} + +/*========================= End of Function ========================*/