[arm64] Set a flag in MonoContext if the fp regs are saved, and only restore them...
authorZoltan Varga <vargaz@gmail.com>
Sat, 5 Nov 2016 02:19:25 +0000 (22:19 -0400)
committerGitHub <noreply@github.com>
Sat, 5 Nov 2016 02:19:25 +0000 (22:19 -0400)
mono/mini/exceptions-arm64.c
mono/utils/mono-context.h

index 6e8889e0b24b78cfac214ff96c0084f4930c6704..9b7f762e9914a1512cbe5e6eacfa7a374e2b7a90 100644 (file)
@@ -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);
index 7e8ad4cb88fa31411986d632e318b243a402d2a8..e8d52d23a289dfc2e2eb355c47df0c318e89ea1f 100644 (file)
@@ -386,6 +386,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)