diff options
author | Zoltan Varga <vargaz@gmail.com> | 2016-11-05 05:19:25 +0300 |
---|---|---|
committer | Zoltan Varga <vargaz@gmail.com> | 2016-11-08 19:19:00 +0300 |
commit | ace3b63d26707ccff5d48a7451fb9be41d9e2531 (patch) | |
tree | 4e76502beb511a25a3243c6f3fafb72b54218d95 | |
parent | 800dbae049e70a0e8adabb40b10f162cb75501db (diff) |
[arm64] Set a flag in MonoContext if the fp regs are saved, and only restore them if they are. These registers are not saved when the context is created from a ucontext. (#3890)
-rw-r--r-- | mono/mini/exceptions-arm64.c | 15 | ||||
-rw-r--r-- | mono/utils/mono-context.h | 5 |
2 files changed, 18 insertions, 2 deletions
diff --git a/mono/mini/exceptions-arm64.c b/mono/mini/exceptions-arm64.c index 6e8889e0b24..9b7f762e991 100644 --- a/mono/mini/exceptions-arm64.c +++ b/mono/mini/exceptions-arm64.c @@ -29,15 +29,21 @@ mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; int i, ctx_reg, size; + guint8 *labels [16]; size = 256; code = start = mono_global_codeman_reserve (size); arm_movx (code, ARMREG_IP0, ARMREG_R0); ctx_reg = ARMREG_IP0; + /* Restore fregs */ + arm_ldrx (code, ARMREG_IP1, ctx_reg, MONO_STRUCT_OFFSET (MonoContext, has_fregs)); + labels [0] = code; + arm_cbzx (code, ARMREG_IP1, 0); for (i = 0; i < 32; ++i) arm_ldrfpx (code, i, ctx_reg, MONO_STRUCT_OFFSET (MonoContext, fregs) + (i * 8)); + mono_arm_patch (labels [0], code, MONO_R_ARM64_CBZ); /* Restore gregs */ // FIXME: Restore less registers // FIXME: fp should be restored later @@ -72,6 +78,7 @@ mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) int i, size, offset, gregs_offset, fregs_offset, ctx_offset, num_fregs, frame_size; MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; + guint8 *labels [16]; size = 512; start = code = mono_global_codeman_reserve (size); @@ -109,13 +116,15 @@ mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) for (i = 0; i < num_fregs; ++i) arm_strfpx (code, ARMREG_D8 + i, ARMREG_FP, fregs_offset + (i * 8)); - /* No need to save/restore fregs, since we don't currently use them */ - /* Load regs from ctx */ code = mono_arm_emit_load_regarray (code, MONO_ARCH_CALLEE_SAVED_REGS, ARMREG_R0, MONO_STRUCT_OFFSET (MonoContext, regs)); /* Load fregs */ + arm_ldrx (code, ARMREG_IP0, ARMREG_R0, MONO_STRUCT_OFFSET (MonoContext, has_fregs)); + labels [0] = code; + arm_cbzx (code, ARMREG_IP0, 0); for (i = 0; i < num_fregs; ++i) arm_ldrfpx (code, ARMREG_D8 + i, ARMREG_R0, MONO_STRUCT_OFFSET (MonoContext, fregs) + (i * 8)); + mono_arm_patch (labels [0], code, MONO_R_ARM64_CBZ); /* Load fp */ arm_ldrx (code, ARMREG_FP, ARMREG_R0, MONO_STRUCT_OFFSET (MonoContext, regs) + (ARMREG_FP * 8)); @@ -384,6 +393,7 @@ mono_arm_throw_exception (gpointer arg, mgreg_t pc, mgreg_t *int_regs, gdouble * memset (&ctx, 0, sizeof (MonoContext)); memcpy (&(ctx.regs [0]), int_regs, sizeof (mgreg_t) * 32); memcpy (&(ctx.fregs [ARMREG_D8]), fp_regs, sizeof (double) * 8); + ctx.has_fregs = 1; ctx.pc = pc; if (mono_object_isinst_checked (exc, mono_defaults.exception_class, &error)) { @@ -412,6 +422,7 @@ mono_arm_resume_unwind (gpointer arg, mgreg_t pc, mgreg_t *int_regs, gdouble *fp memset (&ctx, 0, sizeof (MonoContext)); memcpy (&(ctx.regs [0]), int_regs, sizeof (mgreg_t) * 32); memcpy (&(ctx.fregs [ARMREG_D8]), fp_regs, sizeof (double) * 8); + ctx.has_fregs = 1; ctx.pc = pc; mono_resume_unwind (&ctx); diff --git a/mono/utils/mono-context.h b/mono/utils/mono-context.h index 907c62ee2eb..c5769237e7a 100644 --- a/mono/utils/mono-context.h +++ b/mono/utils/mono-context.h @@ -294,6 +294,11 @@ typedef struct { mgreg_t regs [32]; double fregs [32]; mgreg_t pc; + /* + * fregs might not be initialized if this context was created from a + * ucontext. + */ + mgreg_t has_fregs; } MonoContext; #define MONO_CONTEXT_SET_IP(ctx,ip) do { (ctx)->pc = (mgreg_t)ip; } while (0) |