[mono] Add thunking to s390x for calls that will be patched (#52783)
authorUlrich Weigand <ulrich.weigand@de.ibm.com>
Mon, 17 May 2021 08:48:40 +0000 (10:48 +0200)
committerGitHub <noreply@github.com>
Mon, 17 May 2021 08:48:40 +0000 (10:48 +0200)
Merge https://github.com/mono/mono/pull/21052 into dotnet runtime.

This fixes sporadic crashes due to code being patched non-atomically.

src/mono/mono/mini/exceptions-s390x.c
src/mono/mono/mini/mini-s390x.c
src/mono/mono/mini/mini-s390x.h
src/mono/mono/mini/support-s390x.h [deleted file]
src/mono/mono/mini/tramp-s390x.c

index 0df2507..c79be65 100644 (file)
@@ -61,7 +61,6 @@
 
 #include "mini.h"
 #include "mini-s390x.h"
-#include "support-s390x.h"
 #include "mini-runtime.h"
 #include "aot-runtime.h"
 #include "mono/utils/mono-tls-inline.h"
@@ -119,7 +118,7 @@ mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot)
 
        inited = 1;
        /* call_filter (MonoContext *ctx, unsigned long eip, gpointer exc) */
-       code = start = mono_global_codeman_reserve (512);
+       code = start = (guint8 *) mono_global_codeman_reserve (512);
 
        mono_add_unwind_op_def_cfa (unwind_ops, code, start, STK_BASE, S390_CFA_OFFSET);
        s390_stmg (code, s390_r6, s390_r15, STK_BASE, S390_REG_SAVE_OFFSET);
@@ -314,7 +313,7 @@ mono_arch_get_throw_exception_generic (int size, MonoTrampInfo **info, int corli
        MonoJumpInfo *ji = NULL;
        GSList *unwind_ops = NULL;
 
-       code = start = mono_global_codeman_reserve(size);
+       code = start = (guint8 *) mono_global_codeman_reserve(size);
 
        mono_add_unwind_op_def_cfa (unwind_ops, code, start, STK_BASE, S390_CFA_OFFSET);
        s390_stmg (code, s390_r6, s390_r15, STK_BASE, S390_REG_SAVE_OFFSET);
@@ -569,7 +568,7 @@ mono_arch_unwind_frame (MonoJitTlsData *jit_tls,
                memcpy(new_ctx->uc_mcontext.fpregs.fprs, (*lmf)->fregs, sizeof((*lmf)->fregs));
                MONO_CONTEXT_SET_BP (new_ctx, (*lmf)->ebp);
                MONO_CONTEXT_SET_IP (new_ctx, (*lmf)->eip - 2);
-               *lmf = (*lmf)->previous_lmf;
+               *lmf = (struct MonoLMF *) (*lmf)->previous_lmf;
 
                return TRUE;
        }
index e16cae8..9f27674 100644 (file)
@@ -31,8 +31,9 @@ if (ins->inst_true_bb->native_offset) {                                       \
                s390_jcl (code, cond, displace);                                \
        }                                                                       \
 } else {                                                                       \
-       mono_add_patch_info (cfg, code - cfg->native_code,                      \
-                            MONO_PATCH_INFO_BB, ins->inst_true_bb);            \
+       mono_add_patch_info_rel (cfg, code - cfg->native_code,                  \
+                                MONO_PATCH_INFO_BB, ins->inst_true_bb,         \
+                                MONO_R_S390_RELINS);                           \
        s390_jcl (code, cond, 0);                                               \
 }                                                                              \
 }
@@ -49,8 +50,9 @@ if (ins->inst_target_bb->native_offset) {                                     \
                s390_jcl (code, S390_CC_UN, displace);                          \
        }                                                                       \
 } else {                                                                       \
-       mono_add_patch_info (cfg, code - cfg->native_code,                      \
-                            MONO_PATCH_INFO_BB, ins->inst_target_bb);          \
+       mono_add_patch_info_rel (cfg, code - cfg->native_code,                  \
+                                MONO_PATCH_INFO_BB, ins->inst_target_bb,       \
+                                MONO_R_S390_RELINS);                           \
        s390_jcl (code, S390_CC_UN, 0);                                         \
 }                                                                              \
 }
@@ -79,8 +81,9 @@ if (ins->inst_true_bb->native_offset) {                                       \
        }                                                                       \
 } else {                                                                       \
        s390_##cmp (code, ins->sreg1, ins->sreg2);                              \
-       mono_add_patch_info (cfg, code - cfg->native_code,                      \
-                            MONO_PATCH_INFO_BB, ins->inst_true_bb);            \
+       mono_add_patch_info_rel (cfg, code - cfg->native_code,                  \
+                                MONO_PATCH_INFO_BB, ins->inst_true_bb,         \
+                                MONO_R_S390_RELINS);                           \
        s390_jcl (code, ins->sreg3, 0);                                         \
 }                                                                              \
 }
@@ -119,8 +122,9 @@ if (ins->inst_true_bb->native_offset) {                                     \
                S390_SET (code, s390_r0, ins->backend.data);                    \
                s390_##cmp (code, ins->sreg1, s390_r0);                         \
        }                                                                       \
-       mono_add_patch_info (cfg, code - cfg->native_code,                      \
-                            MONO_PATCH_INFO_BB, ins->inst_true_bb);            \
+       mono_add_patch_info_rel (cfg, code - cfg->native_code,                  \
+                                MONO_PATCH_INFO_BB, ins->inst_true_bb,         \
+                                MONO_R_S390_RELINS);                           \
        s390_jcl (code, ins->sreg3, 0);                                         \
 }                                                                              \
 }
@@ -255,7 +259,6 @@ if (ins->inst_true_bb->native_offset) {                                     \
 
 #include "mini-s390x.h"
 #include "cpu-s390x.h"
-#include "support-s390x.h"
 #include "jit-icalls.h"
 #include "ir-emit.h"
 #include "mini-gc.h"
@@ -341,6 +344,11 @@ static CallInfo * get_call_info (MonoMemPool *, MonoMethodSignature *);
 static guchar * emit_float_to_int (MonoCompile *, guchar *, int, int, int, gboolean);
 static __inline__ void emit_unwind_regs(MonoCompile *, guint8 *, int, int, long);
 static void compare_and_branch(MonoBasicBlock *, MonoInst *, int, gboolean);
+static __inline__ guint8 * emit_call(MonoCompile *, guint8 *, MonoJumpInfoType, gconstpointer);
+static guint8 * emit_thunk(guint8 *, gconstpointer);
+static void create_thunk(MonoCompile *, guint8 *, guint8 *, gpointer);
+static void update_thunk(MonoCompile *, guint8 *, gpointer);
+static void emit_patch_full (MonoCompile *, MonoJumpInfo *, guint8 *, gpointer, int);
 
 /*========================= End of Prototypes ======================*/
 
@@ -2595,10 +2603,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                }
                        break;
                case OP_BREAK: {
-                       mono_add_patch_info (cfg, code - cfg->native_code,
-                                            MONO_PATCH_INFO_JIT_ICALL_ID,
-                                            GUINT_TO_POINTER (MONO_JIT_ICALL_mono_break));
-                       S390_CALL_TEMPLATE (code, s390_r14);
+                       code = emit_call (cfg, code, MONO_PATCH_INFO_JIT_ICALL_ID,
+                                         GUINT_TO_POINTER (MONO_JIT_ICALL_mono_break));
                }
                        break;
                case OP_ADDCC: {
@@ -3562,10 +3568,11 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                                s390_br (code, s390_r1);
                                        }
                                } else {
-                                       mono_add_patch_info (cfg, code - cfg->native_code, 
+                                       mono_add_patch_info_rel (cfg, code - cfg->native_code,
                                                 MONO_PATCH_INFO_METHOD_JUMP, 
-                                                call->method);
+                                                call->method, MONO_R_S390_THUNKED);
                                        S390_BR_TEMPLATE (code, s390_r1);
+                                       cfg->thunk_area += THUNK_SIZE;
                                }
                        }
                }
@@ -3585,10 +3592,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                }
                        break;
                case OP_FCALL: {
-                       call = (MonoCallInst*)ins;
-
-                       mono_call_add_patch_info (cfg, call, code - cfg->native_code);
-                       S390_CALL_TEMPLATE (code, s390_r14);
+                       MonoCallInst *call = (MonoCallInst *) ins;
+                       const MonoJumpInfoTarget patch = mono_call_to_patch (call);
+                       code = emit_call (cfg, code, patch.type, patch.target);
                        if (!cfg->r4fp && call->signature->ret->type == MONO_TYPE_R4)
                                s390_ldebr (code, s390_f0, s390_f0);
                }
@@ -3599,9 +3605,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_VOIDCALL:
                case OP_RCALL:
                case OP_CALL: {
-                       call = (MonoCallInst*)ins;
-                       mono_call_add_patch_info (cfg, call, code - cfg->native_code);
-                       S390_CALL_TEMPLATE (code, s390_r14);
+                       MonoCallInst *call = (MonoCallInst *) ins;
+                       const MonoJumpInfoTarget patch = mono_call_to_patch (call);
+                       code = emit_call (cfg, code, patch.type, patch.target);
                }
                        break;
                case OP_FCALL_REG: {
@@ -3714,16 +3720,14 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        break;
                case OP_THROW: {
                        s390_lgr  (code, s390_r2, ins->sreg1);
-                       mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_JIT_ICALL_ID,
-                                            GUINT_TO_POINTER (MONO_JIT_ICALL_mono_arch_throw_exception));
-                       S390_CALL_TEMPLATE(code, s390_r14);
+                       code = emit_call (cfg, code, MONO_PATCH_INFO_JIT_ICALL_ID,
+                                         GUINT_TO_POINTER (MONO_JIT_ICALL_mono_arch_throw_exception));
                }
                        break;
                case OP_RETHROW: {
                        s390_lgr  (code, s390_r2, ins->sreg1);
-                       mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_JIT_ICALL_ID,
-                                            GUINT_TO_POINTER (MONO_JIT_ICALL_mono_arch_rethrow_exception));
-                       S390_CALL_TEMPLATE(code, s390_r14);
+                       code = emit_call (cfg, code, MONO_PATCH_INFO_JIT_ICALL_ID,
+                                         GUINT_TO_POINTER (MONO_JIT_ICALL_mono_arch_rethrow_exception));
                }
                        break;
                case OP_START_HANDLER: {
@@ -3755,8 +3759,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                }
                        break;
                case OP_CALL_HANDLER: {
-                       mono_add_patch_info (cfg, code-cfg->native_code, 
-                                            MONO_PATCH_INFO_BB, ins->inst_target_bb);
+                       mono_add_patch_info_rel (cfg, code-cfg->native_code,
+                                                MONO_PATCH_INFO_BB, ins->inst_target_bb,
+                                                MONO_R_S390_DIRECT);
                        s390_brasl (code, s390_r14, 0);
                        for (GList *tmp = ins->inst_eh_blocks; tmp != bb->clause_holes; tmp = tmp->prev)
                                mono_cfg_add_try_hole (cfg, ((MonoLeaveClause *) tmp->data)->clause, code, bb);
@@ -3853,9 +3858,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        s390_tm (code, ins->sreg1, byte_offset, bitmask);
                        s390_jo (code, 0); CODEPTR(code, jump);
 
-                       mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_JIT_ICALL_ID,
-                                                        GUINT_TO_POINTER (MONO_JIT_ICALL_mono_generic_class_init));
-                       S390_CALL_TEMPLATE(code, s390_r14);
+                       code = emit_call (cfg, code, MONO_PATCH_INFO_JIT_ICALL_ID,
+                                         GUINT_TO_POINTER (MONO_JIT_ICALL_mono_generic_class_init));
 
                        PTRSLOT (code, jump);
 
@@ -4668,9 +4672,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 
                        s390_ltg (code, s390_r0, 0, ins->sreg1, 0);     
                        s390_jz  (code, 0); CODEPTR(code, br);
-                       mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_JIT_ICALL_ID,
-                                            GUINT_TO_POINTER (MONO_JIT_ICALL_mono_threads_state_poll));
-                       S390_CALL_TEMPLATE (code, s390_r14);
+                       code = emit_call (cfg, code, MONO_PATCH_INFO_JIT_ICALL_ID,
+                                         GUINT_TO_POINTER (MONO_JIT_ICALL_mono_threads_state_poll));
                        PTRSLOT (code, br);
                        break;
                }
@@ -5335,14 +5338,62 @@ mono_arch_register_lowlevel_calls (void)
 
 /**
  *  
+ * @brief Architecture-specific patching
+ * @param[in] @cfg - Compilation control block
+ * @param[in] @code - Start of code
+ * @param[in] @target - Target of patch
+ * @param[in] @relo - Relocation type
+ *
+ * Perform patching action
+ */
+
+static void
+emit_patch_full (MonoCompile *cfg, MonoJumpInfo *ji, guint8 *code,
+                gpointer target, int relo)
+{
+       guint8 *ip = ji->ip.i + code;
+
+       switch (relo) {
+       case MONO_R_S390_RELINS :
+               target = S390_RELATIVE(target, ip);
+               ip += 2;
+               s390_patch_rel (ip, (guint64) target);
+               break;
+       case MONO_R_S390_THUNKED :
+               if (cfg)
+                       create_thunk(cfg, ip, code, target);
+               else
+                       update_thunk(cfg, code, target);
+               break;
+       case MONO_R_S390_DIRECT :
+               S390_EMIT_CALL (ip, target);
+               break;
+       case MONO_R_S390_ADDR :
+               s390_patch_addr (ip, (guint64) target);
+               break;
+       case MONO_R_S390_SWITCH :
+               S390_EMIT_LOAD (ip, target);
+               break;
+       case MONO_R_S390_REL :
+               target = S390_RELATIVE(target, ip);
+               s390_patch_rel (ip, (guint64) target);
+               break;
+       default :
+               g_assert_not_reached();
+       }
+}
+
+/*========================= End of Function ========================*/
+
+/**
+ *
  * @brief Architecture-specific patching of instructions and data
  * 
  * @param[in] @cfg - Compile control block
  * @param[in] @method - Current method
- * @param[in] @code - Current innstruction pointer
+ * @param[in] @code - Current code block
  * @param[in] @ji - Jump information 
- * @param[in] @run_cctors - Whether class constructors need to be initialized 
- * @param[in] @error - Error control block 
+ * @param[in] @target - Target of patch
  *
  * Process the patch data created during the instruction build process. 
  * This resolves jumps, calls, variables etc.
@@ -5351,33 +5402,28 @@ mono_arch_register_lowlevel_calls (void)
 void
 mono_arch_patch_code_new (MonoCompile *cfg, guint8 *code, MonoJumpInfo *ji, gpointer target)
 {
-       unsigned char *ip = ji->ip.i + code;
-       gint64 displace;
-
        switch (ji->type) {
        case MONO_PATCH_INFO_IP:
        case MONO_PATCH_INFO_LDSTR:
        case MONO_PATCH_INFO_TYPE_FROM_HANDLE: 
        case MONO_PATCH_INFO_LDTOKEN: 
        case MONO_PATCH_INFO_EXC:
-               s390_patch_addr (ip, (guint64) target);
+               emit_patch_full (cfg, ji, code, target, MONO_R_S390_ADDR);
                break;
-       case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINE_LAZY_FETCH_ADDR:
-       case MONO_PATCH_INFO_METHOD:
-       case MONO_PATCH_INFO_JIT_ICALL_ID:
+       case MONO_PATCH_INFO_BB:
        case MONO_PATCH_INFO_JIT_ICALL_ADDR:
+       case MONO_PATCH_INFO_JIT_ICALL_ID:
+       case MONO_PATCH_INFO_METHOD:
+               emit_patch_full (cfg, ji, code, target, ji->relocation);
+               break;
+       case MONO_PATCH_INFO_METHOD_JUMP:
        case MONO_PATCH_INFO_RGCTX_FETCH:
-       case MONO_PATCH_INFO_ABS: {
-               S390_EMIT_CALL (ip, target);
+       case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINE_LAZY_FETCH_ADDR:
+       case MONO_PATCH_INFO_ABS:
+               emit_patch_full (cfg, ji, code, target, MONO_R_S390_THUNKED);
                break;
-       }
        case MONO_PATCH_INFO_SWITCH: 
-               /*----------------------------------*/
-               /* ip points at the basr r13,0/j +4 */
-               /* instruction the vtable value     */
-               /* follows this (i.e. ip+6)         */
-               /*----------------------------------*/
-               S390_EMIT_LOAD (ip, target);
+               emit_patch_full(cfg, ji, code, target, MONO_R_S390_SWITCH);
                break;
        case MONO_PATCH_INFO_METHODCONST:
        case MONO_PATCH_INFO_CLASS:
@@ -5385,28 +5431,12 @@ mono_arch_patch_code_new (MonoCompile *cfg, guint8 *code, MonoJumpInfo *ji, gpoi
        case MONO_PATCH_INFO_FIELD:
        case MONO_PATCH_INFO_IID:
        case MONO_PATCH_INFO_EXC_NAME:
-               target = S390_RELATIVE(target, ip);
-               s390_patch_rel (ip, (guint64) target);
-               break;
-       case MONO_PATCH_INFO_R4:
-       case MONO_PATCH_INFO_R8:
-               g_assert_not_reached ();
-               break;
-       case MONO_PATCH_INFO_METHOD_JUMP:
-               displace = (gint64) S390_RELATIVE(target, ip);
-               if ((displace >= INT_MIN) && (displace <= INT_MAX)) 
-                       s390_jg (ip, (gint32) displace);
-               else {
-                       S390_SET (ip, s390_r1, target);
-                       s390_br  (ip, s390_r1);
-               }
+               emit_patch_full(cfg, ji, code, target, MONO_R_S390_REL);
                break;
        case MONO_PATCH_INFO_NONE:
                break;
        default:
-               target = S390_RELATIVE(target, ip);
-               ip += 2;
-               s390_patch_rel (ip, (guint64) target);
+               emit_patch_full (cfg, ji, code, target, MONO_R_S390_RELINS);
        }
 }
 
@@ -5675,10 +5705,8 @@ if ((strcmp(method->klass->name_space,"") == 0) &&
                /*
                 * On return from this call r2 have the address of the &lmf
                 */
-               mono_add_patch_info (cfg, code - cfg->native_code, 
-                               MONO_PATCH_INFO_JIT_ICALL_ID,
-                               GUINT_TO_POINTER (MONO_JIT_ICALL_mono_tls_get_lmf_addr_extern));
-               S390_CALL_TEMPLATE(code, s390_r1);
+               code = emit_call (cfg, code, MONO_PATCH_INFO_JIT_ICALL_ID,
+                                 GUINT_TO_POINTER (MONO_JIT_ICALL_mono_tls_get_lmf_addr_extern));
 
                /*
                 * Set lmf.lmf_addr = jit_tls->lmf
@@ -5899,6 +5927,9 @@ mono_arch_emit_epilog (MonoCompile *cfg)
        /* Restore the unwind state to be the same as before the epilog */
        mono_emit_unwind_op_restore_state (cfg, code);
 
+       /* Round up for start of any thunk entries */
+       code = (guint8 *) ((((uintptr_t) code + 7) >> 3) << 3);
+
        set_code_cursor (cfg, code);
 
 }
@@ -5985,7 +6016,9 @@ mono_arch_emit_exceptions (MonoCompile *cfg)
                                patch_info->type              = MONO_PATCH_INFO_JIT_ICALL_ID;
                                patch_info->data.jit_icall_id = MONO_JIT_ICALL_mono_arch_throw_corlib_exception;
                                patch_info->ip.i              = code - cfg->native_code;
+                               patch_info->relocation        = MONO_R_S390_THUNKED;
                                S390_BR_TEMPLATE (code, s390_r1);
+                               cfg->thunk_area += THUNK_SIZE;
                        }
                        break;
                }
@@ -5994,6 +6027,10 @@ mono_arch_emit_exceptions (MonoCompile *cfg)
                        break;
                }
        }
+
+       /* Round up for start of any thunk entries */
+       code = (guint8 *) ((((uintptr_t) code + 7) >> 3) << 3);
+
        set_code_cursor (cfg, code);
 }
 
@@ -7003,3 +7040,146 @@ mono_arch_load_function (MonoJitICallId jit_icall_id)
 }
 
 /*========================= End of Function ========================*/
+
+/**
+ *
+ * @brief Emit call to thunked code
+ *
+ * @param[in] @cfg - configuration data
+ * @param[inout] @code - where to emit call
+ * @param[in] @call - call instruction
+ * @returns Pointer to next code area
+ *
+ */
+
+static __inline__ guint8*
+emit_call (MonoCompile *cfg, guint8 *code, MonoJumpInfoType type, gconstpointer target)
+{
+       mono_add_patch_info_rel (cfg, code-cfg->native_code, type,
+                                target, MONO_R_S390_THUNKED);
+       S390_CALL_TEMPLATE (code, s390_r14);
+       cfg->thunk_area += THUNK_SIZE;
+       return code;
+}
+
+/*========================= End of Function ========================*/
+
+/**
+ *
+ * @brief Emit thunk for an indirect call
+ *
+ * @param[inout] @code - where to emit thunk
+ * @param[in] @target - thunk target
+ * @returns Pointer to next code area
+ *
+ */
+
+static guint8*
+emit_thunk (guint8 *code, gconstpointer target)
+{
+       *(guint64*)code = (guint64)target;
+       code += sizeof (guint64);
+
+       return code;
+}
+
+/*========================= End of Function ========================*/
+
+/**
+ *
+ * @brief Create thunk
+ *
+ * @param[in] @cfg - Compiler configuration
+ * @param[inout] @code - where to emit thunk
+ * @param[in] @target - thunk target
+ *
+ * Create a new thunk
+ *
+ */
+
+static void
+create_thunk (MonoCompile *cfg, guint8 *ip, guint8 *code, gpointer target)
+{
+       guint8 *thunks;
+       int thunks_size;
+
+       /*
+        * This can be called multiple times during JITting,
+        * save the current position in cfg->arch to avoid
+        * doing a O(n^2) search.
+        */
+       if (!cfg->arch.thunks) {
+               cfg->arch.thunks = cfg->thunks;
+               cfg->arch.thunks_size = cfg->thunk_area;
+       }
+       thunks = (guint8 *) cfg->arch.thunks;
+       thunks_size = cfg->arch.thunks_size;
+       if (!thunks_size) {
+               g_print ("thunk failed %p->%p, thunk space=%d method %s", code, target, thunks_size, mono_method_full_name (cfg->method, TRUE));
+               g_assert_not_reached ();
+       }
+
+       g_assert (*(guint64 *)thunks == 0);
+       emit_thunk (thunks, target);
+
+       cfg->arch.thunks += THUNK_SIZE;
+       cfg->arch.thunks_size -= THUNK_SIZE;
+
+       S390_EMIT_CALL(ip, thunks);
+}
+
+/*========================= End of Function ========================*/
+
+/**
+ *
+ * @brief Update thunk
+ *
+ * @param[in] @cfg - Compiler configuration
+ * @param[inout] @code - where to emit thunk
+ * @param[in] @target - thunk target
+ *
+ * Update an existing thunk
+ *
+ */
+
+static void
+update_thunk (MonoCompile *cfg, guint8 *code, gpointer target)
+{
+        MonoJitInfo *ji;
+        MonoThunkJitInfo *info;
+        guint8 *thunks;
+        guint8 *orig_target;
+        guint8 *target_thunk;
+       int thunks_size;
+
+       ji = mini_jit_info_table_find ((char*)code);
+       g_assert (ji);
+       info = mono_jit_info_get_thunk_info (ji);
+       g_assert (info);
+
+       thunks = (guint8*)ji->code_start + info->thunks_offset;
+       thunks_size = info->thunks_size;
+
+       /*
+        * We're pointing at the start of jump to thunk,
+        * but mono_arch_get_call_target expects we're pointing
+        * after the branch so we adjust
+        */
+       orig_target = mono_arch_get_call_target (code + 6);
+
+       target_thunk = NULL;
+       if (orig_target >= thunks && orig_target < thunks + thunks_size) {
+               /* The call already points to a thunk, because of trampolines etc. */
+               target_thunk = orig_target;
+       } else {
+               g_print ("thunk failed %p->%p, thunk space=%d method %s",
+                        code, target, thunks_size,
+                        cfg ? mono_method_full_name (cfg->method, TRUE)
+                            : mono_method_full_name (jinfo_get_method (ji), TRUE));
+               g_assert_not_reached ();
+       }
+
+       emit_thunk (target_thunk, target);
+}
+
+/*========================= End of Function ========================*/
index 2b94792..d7d3566 100644 (file)
@@ -38,6 +38,8 @@ typedef struct MonoCompileArch {
        int         fpSize;             /** Size of floating point save area */
        MonoInst    *ss_tramp_var;      /** Single-step variable */
        MonoInst    *bp_tramp_var;      /** Breakpoint variable */
+       guint8      *thunks;            /** Thunking area */
+       int         thunks_size;        /** Size of thunking area */
 } MonoCompileArch;
 
 typedef struct
@@ -90,6 +92,17 @@ struct SeqPointInfo {
 
 #define S390_FP_SAVE_MASK              0xf0
 
+/* Thunk: 8 byte pointer */
+#define THUNK_SIZE                     8
+
+/* Relocation types */
+#define MONO_R_S390_RELINS     1       /* JGxx - relative jump */
+#define MONO_R_S390_THUNKED    2       /* Thunked call */
+#define MONO_R_S390_DIRECT     3       /* Direct call */
+#define MONO_R_S390_ADDR       4       /* Address */
+#define MONO_R_S390_SWITCH     5       /* Switch */
+#define MONO_R_S390_REL                6       /* Relative displacement */
+
 /*===============================================*/
 /* Definitions used by mini-codegen.c            */
 /*===============================================*/
@@ -166,13 +179,13 @@ struct SeqPointInfo {
 
 #define MONO_ARCH_INIT_TOP_LMF_ENTRY(lmf) do { (lmf)->ebp = -1; } while (0)
 
-/*------------------------------------------------------------------*/
-/*                                                                  */
-/* Name                - s390_patch_rel                                    */
-/*                                                                  */
-/* Function    - Patch the code with a given offset.               */
-/*                                                                  */
-/*------------------------------------------------------------------*/
+/**
+ *
+ * @brief Patch the code with a given offset
+ * @param[in] @code - Area to patch
+ * @param[in] @target - Value to patch with
+ *
+ */
 
 static void inline
 s390_patch_rel (guchar *code, guint64 target)
@@ -186,13 +199,13 @@ s390_patch_rel (guchar *code, guint64 target)
 
 /*========================= End of Function ========================*/
 
-/*------------------------------------------------------------------*/
-/*                                                                  */
-/* Name                - s390_patch_addr                                   */
-/*                                                                  */
-/* Function    - Patch the code with a given address.              */
-/*                                                                  */
-/*------------------------------------------------------------------*/
+/**
+ *
+ * @brief Patch the code with a given address
+ * @param[in] @code - Area to patch
+ * @param[in] @target - Address to patch with
+ *
+ */
 
 static void inline
 s390_patch_addr (guchar *code, guint64 target)
@@ -248,4 +261,92 @@ s390_patch_addr (guchar *code, guint64 target)
 
 /*========================= End of Function ========================*/
 
+#define S390_SET(loc, dr, v)                                   \
+       do {                                                    \
+               guint64 val = (guint64) v;                      \
+               if (s390_is_imm16(val)) {                       \
+                       s390_lghi(loc, dr, val);                \
+               } else if (s390_is_uimm16(val)) {               \
+                       s390_llill(loc, dr, val);               \
+               } else if (s390_is_imm32(val)) {                \
+                       s390_lgfi(loc, dr, val);                \
+               } else if (s390_is_uimm32(val)) {               \
+                       s390_llilf(loc, dr, val);               \
+               } else {                                        \
+                       guint32 hi = (val) >> 32;               \
+                       guint32 lo = (val) & 0xffffffff;        \
+                       s390_iihf(loc, dr, hi);                 \
+                       s390_iilf(loc, dr, lo);                 \
+               }                                               \
+       } while (0)
+
+#define S390_LONG(loc, opy, op, r, ix, br, off)                                \
+       if (s390_is_imm20(off)) {                                       \
+               s390_##opy (loc, r, ix, br, off);                       \
+       } else {                                                        \
+               if (ix == 0) {                                          \
+                       S390_SET(loc, s390_r13, off);                   \
+                       s390_la (loc, s390_r13, s390_r13, br, 0);       \
+               } else {                                                \
+                       s390_la   (loc, s390_r13, ix, br, 0);           \
+                       S390_SET  (loc, s390_r0, off);                  \
+                       s390_agr  (loc, s390_r13, s390_r0);             \
+               }                                                       \
+               s390_##op (loc, r, 0, s390_r13, 0);                     \
+       }
+
+#define S390_SET_MASK(loc, dr, v)                              \
+       do {                                                    \
+               if (s390_is_imm16 (v)) {                        \
+                       s390_lghi (loc, dr, v);                 \
+               } else if (s390_is_imm32 (v)) {                 \
+                       s390_lgfi (loc, dr, v);                 \
+               } else {                                        \
+                       gint64 val = (gint64) v;                \
+                       guint32 hi = (val) >> 32;               \
+                       guint32 lo = (val) & 0xffffffff;        \
+                       s390_iilf(loc, dr, lo);                 \
+                       s390_iihf(loc, dr, hi);                 \
+               }                                               \
+       } while (0)
+
+#define S390_CALL_TEMPLATE(loc, r)                             \
+       do {                                                    \
+               s390_lgrl (loc, r, 0);                          \
+               s390_basr (loc, s390_r14, r);                   \
+       } while (0)
+
+#define S390_BR_TEMPLATE(loc, r)                               \
+       do {                                                    \
+               s390_lgrl (loc, r, 0);                          \
+               s390_br   (loc, r);                             \
+       } while (0)
+
+#define S390_LOAD_TEMPLATE(loc, r)                             \
+       do {                                                    \
+               s390_iihf (loc, r, 0);                          \
+               s390_iilf (loc, r, 0);                          \
+       } while (0)
+
+#define S390_EMIT_CALL(loc, t)                                 \
+       do {                                                    \
+               uintptr_t rel;                                  \
+               uintptr_t p = (uintptr_t) loc;                  \
+               rel = ((uintptr_t) t - (uintptr_t) loc) >> 1;   \
+               p += 2;                                         \
+               *(guint32 *) p = rel;                           \
+       } while (0)
+
+#define S390_EMIT_LOAD(loc, v)                                 \
+       do {                                                    \
+               gint64 val = (gint64) v;                        \
+               guint32 hi = (val) >> 32;                       \
+               guint32 lo = (val) & 0xffffffff;                \
+               uintptr_t p = (uintptr_t) loc;                  \
+               p += 2;                                         \
+               *(guint32 *) p = hi;                            \
+               p += 6;                                         \
+               *(guint32 *) p = lo;                            \
+       } while (0)
+
 #endif /* __MONO_MINI_S390X_H__ */  
diff --git a/src/mono/mono/mini/support-s390x.h b/src/mono/mono/mini/support-s390x.h
deleted file mode 100644 (file)
index 8856f77..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/**
- * \file
- */
-
-#ifndef __MONO_SUPPORT_S390X_H__
-#define __MONO_SUPPORT_S390X_H__
-
-#define S390_SET(loc, dr, v)                                   \
-       do {                                                    \
-               guint64 val = (guint64) v;                      \
-               if (s390_is_imm16(val)) {                       \
-                       s390_lghi(loc, dr, val);                \
-               } else if (s390_is_uimm16(val)) {               \
-                       s390_llill(loc, dr, val);               \
-               } else if (s390_is_imm32(val)) {                \
-                       s390_lgfi(loc, dr, val);                \
-               } else if (s390_is_uimm32(val)) {               \
-                       s390_llilf(loc, dr, val);               \
-               } else {                                        \
-                       guint32 hi = (val) >> 32;               \
-                       guint32 lo = (val) & 0xffffffff;        \
-                       s390_iihf(loc, dr, hi);                 \
-                       s390_iilf(loc, dr, lo);                 \
-               }                                               \
-       } while (0)
-
-#define S390_LONG(loc, opy, op, r, ix, br, off)                                \
-       if (s390_is_imm20(off)) {                                       \
-               s390_##opy (loc, r, ix, br, off);                       \
-       } else {                                                        \
-               if (ix == 0) {                                          \
-                       S390_SET(loc, s390_r13, off);                   \
-                       s390_la (loc, s390_r13, s390_r13, br, 0);       \
-               } else {                                                \
-                       s390_la   (loc, s390_r13, ix, br, 0);           \
-                       S390_SET  (loc, s390_r0, off);                  \
-                       s390_agr  (loc, s390_r13, s390_r0);             \
-               }                                                       \
-               s390_##op (loc, r, 0, s390_r13, 0);                     \
-       }
-
-#define S390_SET_MASK(loc, dr, v)                              \
-       do {                                                    \
-               if (s390_is_imm16 (v)) {                        \
-                       s390_lghi (loc, dr, v);                 \
-               } else if (s390_is_imm32 (v)) {                 \
-                       s390_lgfi (loc, dr, v);                 \
-               } else {                                        \
-                       gint64 val = (gint64) v;                \
-                       guint32 hi = (val) >> 32;               \
-                       guint32 lo = (val) & 0xffffffff;        \
-                       s390_iilf(loc, dr, lo);                 \
-                       s390_iihf(loc, dr, hi);                 \
-               }                                               \
-       } while (0)
-
-#define S390_CALL_TEMPLATE(loc, r)                             \
-       do {                                                    \
-               s390_iihf (loc, r, 0);                          \
-               s390_iilf (loc, r, 0);                          \
-               s390_basr (loc, s390_r14, r);                   \
-       } while (0)
-
-#define S390_BR_TEMPLATE(loc, r)                               \
-       do {                                                    \
-               s390_iihf (loc, r, 0);                          \
-               s390_iilf (loc, r, 0);                          \
-               s390_br   (loc, r);                             \
-       } while (0)
-
-#define S390_LOAD_TEMPLATE(loc, r)                             \
-       do {                                                    \
-               s390_iihf (loc, r, 0);                          \
-               s390_iilf (loc, r, 0);                          \
-       } while (0)
-
-#define S390_EMIT_CALL(loc, t)                                 \
-       do {                                                    \
-               gint64 val = (gint64) t;                        \
-               guint32 hi = (val) >> 32;                       \
-               guint32 lo = (val) & 0xffffffff;                \
-               uintptr_t p = (uintptr_t) loc;                  \
-               p += 2;                                         \
-               *(guint32 *) p = hi;                            \
-               p += 6;                                         \
-               *(guint32 *) p = lo;                            \
-       } while (0)
-
-#define S390_EMIT_LOAD(loc, v)                                 \
-       do {                                                    \
-               gint64 val = (gint64) v;                        \
-               guint32 hi = (val) >> 32;                       \
-               guint32 lo = (val) & 0xffffffff;                \
-               uintptr_t p = (uintptr_t) loc;                  \
-               p += 2;                                         \
-               *(guint32 *) p = hi;                            \
-               p += 6;                                         \
-               *(guint32 *) p = lo;                            \
-       } while (0)
-
-#endif /* __MONO_SUPPORT_S390X_H__ */
index 9634169..d035295 100644 (file)
@@ -50,7 +50,6 @@
 #include "mini.h"
 #include "mini-s390x.h"
 #include "mini-runtime.h"
-#include "support-s390x.h"
 #include "jit-icalls.h"
 #include "debugger-agent.h"
 #include "mono/utils/mono-tls-inline.h"
@@ -245,43 +244,75 @@ mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gbo
        return buf;
 }
 
-/*------------------------------------------------------------------*/
-/*                                                                  */
-/* Name                - mono_arch_patch_callsite                          */
-/*                                                                  */
-/* Function    - Patch a non-virtual callsite so it calls @addr.   */
-/*                                                                  */
-/*------------------------------------------------------------------*/
+/**
+ *
+ * @brief Locate the address of the thunk target
+ *
+ * @param[in] @code - Instruction following the branch and save
+ * @returns Address of the thunk code
+ *
+ * A thunk call is a sequence of:
+ *     lgrl    rx,tgt  Load address of target          (.-6)
+ *     basr    rx,rx   Branch and save to that address (.), or,
+ *     br      r1      Jump to target                  (.)
+ *
+ * The target of that code is a thunk which:
+ * tgt:        .quad   target          Destination
+ */
+
+guint8 *
+mono_arch_get_call_target (guint8 *code)
+{
+       guint8 *thunk;
+       guint32 rel;
+
+       /*
+        * Determine thunk address by adding the relative offset
+        * in the lgrl to its location
+        */
+       rel = *(guint32 *) ((uintptr_t) code - 4);
+       thunk = (guint8 *) ((uintptr_t) code - 6) + (rel * 2);
+
+       return(thunk);
+}
+
+/*========================= End of Function ========================*/
+
+/**
+ *
+ * @brief Patch the callsite
+ *
+ * @param[in] @method_start - first instruction of method
+ * @param[in] @orig_code - Instruction following the branch and save
+ * @param[in] @addr - New value for target of call
+ *
+ * Patch a call. The call is either a 'thunked' call identified by the BASR R14,R14
+ * instruction or a direct call
+ */
 
 void
 mono_arch_patch_callsite (guint8 *method_start, guint8 *orig_code, guint8 *addr)
 {
-       gint32 displace;
-       unsigned short opcode;
-
-       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);
-       }
+       guint64 *thunk;
+
+       thunk = (guint64 *) mono_arch_get_call_target(orig_code - 2);
+       *thunk = (guint64) addr;
 }
 
 /*========================= End of Function ========================*/
 
-/*------------------------------------------------------------------*/
-/*                                                                  */
-/* Name                - mono_arch_patch_plt_entry.                        */
-/*                                                                  */
-/* Function    - Patch a PLT entry - unused as yet.                */
-/*                                                                  */
-/*------------------------------------------------------------------*/
+/**
+ *
+ * @brief Patch PLT entry (AOT only)
+ *
+ * @param[in] @code - Location of PLT
+ * @param[in] @got - Global Offset Table
+ * @param[in] @regs - Registers at the time
+ * @param[in] @addr - Target address
+ *
+ * Not reached on s390x until we have AOT support
+ *
+ */
 
 void
 mono_arch_patch_plt_entry (guint8 *code, gpointer *got, host_mgreg_t *regs, guint8 *addr)
@@ -291,14 +322,17 @@ mono_arch_patch_plt_entry (guint8 *code, gpointer *got, host_mgreg_t *regs, guin
 
 /*========================= End of Function ========================*/
 
-/*------------------------------------------------------------------*/
-/*                                                                  */
-/* Name                - mono_arch_create_trampoline_code                  */
-/*                                                                  */
-/* Function    - Create the designated type of trampoline according*/
-/*                to the 'tramp_type' parameter.                    */
-/*                                                                  */
-/*------------------------------------------------------------------*/
+/**
+ *
+ * @brief Architecture-specific trampoline creation
+ *
+ * @param[in] @tramp_type - Type of trampoline
+ * @param[out] @info - Pointer to trampoline information
+ * @param[in] @aot - AOT indicator
+ *
+ * Create a generic trampoline
+ *
+ */
 
 guchar*
 mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInfo **info, gboolean aot)
@@ -520,13 +554,16 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf
 
 /*========================= End of Function ========================*/
 
-/*------------------------------------------------------------------*/
-/*                                                                  */
-/* Name                - mono_arch_invalidate_method                       */
-/*                                                                  */
-/* Function    -                                                   */
-/*                                                                  */
-/*------------------------------------------------------------------*/
+/**
+ *
+ * @brief Architecture-specific method invalidation
+ *
+ * @param[in] @func - Function to call
+ * @param[in] @func_arg - Argument to invalidation function
+ *
+ * Call an error routine so peple can fix their code
+ *
+ */
 
 void
 mono_arch_invalidate_method (MonoJitInfo *ji, void *func, gpointer func_arg)
@@ -542,13 +579,18 @@ mono_arch_invalidate_method (MonoJitInfo *ji, void *func, gpointer func_arg)
 
 /*========================= End of Function ========================*/
 
-/*------------------------------------------------------------------*/
-/*                                                                  */
-/* Name                - mono_arch_create_specific_trampoline              */
-/*                                                                  */
-/* Function    - Creates the given kind of specific trampoline     */
-/*                                                                  */
-/*------------------------------------------------------------------*/
+/**
+ *
+ * @brief Architecture-specific specific trampoline creation
+ *
+ * @param[in] @arg1 - Argument to trampoline being created
+ * @param[in] @tramp_type - Trampoline type
+ * @param[in] @domain - Mono Domain
+ * @param[out] @code_len - Length of trampoline created
+ *
+ * Create the specified kind of trampoline
+ *
+ */
 
 gpointer
 mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoMemoryManager *mem_manager, guint32 *code_len)
@@ -591,13 +633,17 @@ mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_ty
 
 /*========================= End of Function ========================*/
 
-/*------------------------------------------------------------------*/
-/*                                                                  */
-/* Name                - mono_arch_create_rgctx_lazy_fetch_trampoline      */
-/*                                                                  */
-/* Function    -                                                   */
-/*                                                                  */
-/*------------------------------------------------------------------*/
+/**
+ *
+ * @brief Architecture-specific RGCTX lazy fetch trampoline
+ *
+ * @param[in] @slot - Instance
+ * @param[out] @info - Mono Trampoline Information
+ * @param[in] @aot - AOT indicator
+ *
+ * Create the specified kind of trampoline
+ *
+ */
 
 gpointer
 mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info, gboolean aot)
@@ -714,14 +760,16 @@ mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info
 
 /*========================= End of Function ========================*/
 
-/*------------------------------------------------------------------*/
-/*                                                                  */
-/* Name        - mono_arch_get_static_rgctx_trampoline             */
-/*                                                                  */
-/* Function    - Create a trampoline which sets RGCTX_REG to ARG       */
-/*               then jumps to ADDR.                               */
-/*                                                                  */
-/*------------------------------------------------------------------*/
+/**
+ *
+ * @brief Architecture-specific static RGCTX lazy fetch trampoline
+ *
+ * @param[in] @arg - Argument to trampoline being created
+ * @param[out] @addr - Target
+ *
+ * Create a trampoline which sets RGCTX_REG to ARG
+ *                then jumps to ADDR.
+ */
 
 gpointer
 mono_arch_get_static_rgctx_trampoline (MonoMemoryManager *mem_manager, gpointer arg, gpointer addr)