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); \
} \
}
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); \
} \
}
} \
} 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); \
} \
}
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); \
} \
}
#include "mini-s390x.h"
#include "cpu-s390x.h"
-#include "support-s390x.h"
#include "jit-icalls.h"
#include "ir-emit.h"
#include "mini-gc.h"
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 ======================*/
}
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: {
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;
}
}
}
}
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);
}
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: {
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: {
}
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);
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);
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;
}
/**
*
+ * @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.
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:
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);
}
}
/*
* 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
/* 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);
}
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;
}
break;
}
}
+
+ /* Round up for start of any thunk entries */
+ code = (guint8 *) ((((uintptr_t) code + 7) >> 3) << 3);
+
set_code_cursor (cfg, code);
}
}
/*========================= 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 ========================*/
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
#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 */
/*===============================================*/
#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)
/*========================= 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)
/*========================= 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__ */
+++ /dev/null
-/**
- * \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__ */
#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"
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)
/*========================= 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)
/*========================= 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)
/*========================= 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)
/*========================= 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)
/*========================= 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)