Fix regression in thread name reporting in the profiler.
[mono.git] / mono / mini / tramp-s390x.c
index 2cf715a7c099087bf12d6a484bfa5dbbb3852044..8f2875afdff874cb0cf258b322d5061f3b3087d5 100644 (file)
@@ -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                  */
@@ -74,7 +77,7 @@
 
 /*------------------------------------------------------------------*/
 /*                                                                  */
-/* Name                - mono_arch_get_unbox_trampoline                        */
+/* Name                - mono_arch_get_unbox_trampoline                    */
 /*                                                                  */
 /* Function    - Return a pointer to a trampoline which does the   */
 /*               unboxing before calling the method.               */
@@ -94,14 +97,7 @@ mono_arch_get_unbox_trampoline (MonoMethod *method, gpointer addr)
        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;
-
-       mono_domain_lock (domain);
-       start = code = mono_code_manager_reserve (domain->code_mp, 28);
-       mono_domain_unlock (domain);
+       start = code = mono_domain_code_reserve (domain, 28);
 
        s390_basr (code, s390_r1, 0);
        s390_j    (code, 6);
@@ -121,9 +117,9 @@ mono_arch_get_unbox_trampoline (MonoMethod *method, gpointer addr)
 
 /*------------------------------------------------------------------*/
 /*                                                                  */
-/* Name                - mono_arch_patch_callsite                              */
+/* Name                - mono_arch_patch_callsite                          */
 /*                                                                  */
-/* Function    - Patch a non-virtual callsite so it calls @addr.       */
+/* Function    - Patch a non-virtual callsite so it calls @addr.   */
 /*                                                                  */
 /*------------------------------------------------------------------*/
 
@@ -159,8 +155,16 @@ mono_arch_patch_callsite (guint8 *method_start, guint8 *orig_code, guint8 *addr)
 
 /*========================= End of Function ========================*/
 
+/*------------------------------------------------------------------*/
+/*                                                                  */
+/* Name                - mono_arch_patch_plt_entry.                        */
+/*                                                                  */
+/* Function    - Patch a PLT entry - unused as yet.                */
+/*                                                                  */
+/*------------------------------------------------------------------*/
+
 void
-mono_arch_patch_plt_entry (guint8 *code, guint8 *addr)
+mono_arch_patch_plt_entry (guint8 *code, gpointer *got, mgreg_t *regs, guint8 *addr)
 {
        g_assert_not_reached ();
 }
@@ -169,14 +173,14 @@ mono_arch_patch_plt_entry (guint8 *code, guint8 *addr)
 
 /*------------------------------------------------------------------*/
 /*                                                                  */
-/* Name                - mono_arch_nullify_class_init_trampoline               */
+/* Name                - mono_arch_nullify_class_init_trampoline           */
 /*                                                                  */
-/* Function    - Nullify a call which calls a class init trampoline    */
+/* Function    - Nullify a call which calls a class init trampoline*/
 /*                                                                  */
 /*------------------------------------------------------------------*/
 
 void
-mono_arch_nullify_class_init_trampoline (guint8 *code, gssize *regs)
+mono_arch_nullify_class_init_trampoline (guint8 *code, mgreg_t *regs)
 {
        char patch[2] = {0x07, 0x00};
 
@@ -187,126 +191,51 @@ mono_arch_nullify_class_init_trampoline (guint8 *code, gssize *regs)
 
 /*========================= End of Function ========================*/
 
-void
-mono_arch_nullify_plt_entry (guint8 *code)
-{
-       g_assert_not_reached ();
-}
-
-/*========================= End of Function ========================*/
-
 /*------------------------------------------------------------------*/
 /*                                                                  */
-/* Name                - mono_arch_get_vcall_slot                              */
+/* Name                - mono_arch_get_nullified_class_init                */
 /*                                                                  */
-/* 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               */
+/* Function    - Nullify a PLT entry call.                         */
 /*                                                                  */
 /*------------------------------------------------------------------*/
 
 gpointer
-mono_arch_get_vcall_slot (guint8 *code, gpointer *regs, int *displacement)
+mono_arch_get_nullified_class_init_trampoline (MonoTrampInfo **info)
 {
-       int reg, lkReg;
-       guchar* base;
-       unsigned short opcode;
-       char *sp;
+       guint8 *buf, *code;
 
-       // We are passed sp instead of the register array
-       sp = (char*)regs;
+       code = buf = mono_global_codeman_reserve (16);
 
-       *displacement = 0;
+       s390_br (code, s390_r14);
 
-       opcode = *((unsigned short *) (code - 6));
-       if (opcode == 0xc0e5)
-               /* This is the 'brasl' instruction */
-               return NULL;
-
-       /*-----------------------------------*/
-       /* This is a bras 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 (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)));
-       if (lkReg != 1)
-               /* Non virtual call */
-               return NULL;
-
-       return base;
-}
-
-/*========================= End of Function ========================*/
+       if (info)
+               *info = mono_tramp_info_create ("nullified_class_init_trampoline", 
+                                               buf, code - buf, NULL, NULL);
 
-gpointer*
-mono_arch_get_vcall_slot_addr (guint8* code, gpointer *regs)
-{
-       gpointer vt;
-       int displacement;
-       vt = mono_arch_get_vcall_slot (code, regs, &displacement);
-       if (!vt)
-               return NULL;
-       return (gpointer*)((char*)vt + displacement);
+       return (buf);
 }
 
 /*========================= End of Function ========================*/
 
 /*------------------------------------------------------------------*/
 /*                                                                  */
-/* Name                - mono_arch_create_trampoline_code                            */
+/* 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)
 {
-
+       char *tramp_name;
        guint8 *buf, *tramp, *code;
        int i, offset, lmfOffset;
+       GSList *unwind_ops = NULL;
+       MonoJumpInfo *ji = NULL;
+
+       g_assert (!aot);
 
        /* Now we'll create in 'buf' the S/390 trampoline code. This
           is the trampoline code common to all methods  */
@@ -318,7 +247,7 @@ mono_arch_create_trampoline_code (MonoTrampolineType tramp_type)
          stack size big enough to save our registers.
          -----------------------------------------------------------*/
                
-       s390_stmg (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
+       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);
@@ -403,12 +332,14 @@ mono_arch_create_trampoline_code (MonoTrampolineType tramp_type)
        /*---------------------------------------------------------------*/     
        /* 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]));
-       }                                               
+       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                        */
@@ -416,9 +347,8 @@ mono_arch_create_trampoline_code (MonoTrampolineType tramp_type)
                                
        /* Set arguments */
 
-       /* Arg 1: gssize *regs. We pass sp instead */
-       s390_lgr  (buf, s390_r2, STK_BASE);
-       s390_ahi  (buf, s390_r2, CREATE_STACK_SIZE);
+       /* Arg 1: mgreg_t *regs. We pass sp instead */
+       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) {
@@ -427,10 +357,11 @@ mono_arch_create_trampoline_code (MonoTrampolineType tramp_type)
                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 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 */
                
@@ -471,14 +402,22 @@ mono_arch_create_trampoline_code (MonoTrampolineType tramp_type)
        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);
        
+       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);
 
@@ -489,9 +428,9 @@ mono_arch_create_trampoline_code (MonoTrampolineType tramp_type)
 
 /*------------------------------------------------------------------*/
 /*                                                                  */
-/* Name                - mono_arch_create_specific_trampoline                  */
+/* Name                - mono_arch_create_specific_trampoline              */
 /*                                                                  */
-/* Function    - Creates the given kind of specific trampoline         */
+/* Function    - Creates the given kind of specific trampoline     */
 /*                                                                  */
 /*------------------------------------------------------------------*/
 
@@ -508,16 +447,14 @@ mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_ty
        /* purpose is to provide the generic part with the          */
        /* MonoMethod *method pointer. We'll use r1 to keep it.     */
        /*----------------------------------------------------------*/
-       mono_domain_lock (domain);
-       code = buf = mono_code_manager_reserve (domain->code_mp, SPECIFIC_TRAMPOLINE_SIZE);
-       mono_domain_unlock (domain);
+       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);
        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);
@@ -533,18 +470,215 @@ mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_ty
 
 /*========================= End of Function ========================*/
 
+/*------------------------------------------------------------------*/
+/*                                                                  */
+/* Name                - mono_arch_create_rgctx_lazy_fetch_trampoline      */
+/*                                                                  */
+/* Function    -                                                   */
+/*                                                                  */
+/*------------------------------------------------------------------*/
+
 gpointer
-mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 encoded_offset)
+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, 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);
+       }
+
+       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);
+
+       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);
+}      
 
-guint32
-mono_arch_get_rgctx_lazy_fetch_offset (gpointer *regs)
+/*========================= 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)
 {
-       /* FIXME: implement! */
-       g_assert_not_reached ();
-       return 0;
+       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_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_arch_flush_icache (start, code - start);
+
+       return(start);
+}      
+
+/*========================= 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;
+       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);
+
+       if (info)
+               *info = mono_tramp_info_create ("generic_class_init_trampoline", buf, code - buf, ji, unwind_ops);
+
+       return(buf);
 }
+
+/*========================= End of Function ========================*/