2010-07-04 Zoltan Varga <vargaz@gmail.com>
authorZoltan Varga <vargaz@gmail.com>
Sun, 4 Jul 2010 20:07:56 +0000 (20:07 -0000)
committerZoltan Varga <vargaz@gmail.com>
Sun, 4 Jul 2010 20:07:56 +0000 (20:07 -0000)
* unwind.c (decode_lsda): Use read32 for reading 32 bit quantities.

* tramp-arm.c (mono_arch_create_generic_trampoline): Save the original sp to
lmf->iregs [ARMREG_IP] to be consistent with mono_arch_emit_prolog ().

* mini-arm.h (MonoLMF): Remove unused fregs field, add comments for other fields.

* exceptions-arm.c: Clean up the handling of LMFs. Add LLVM exception trampolines.

svn path=/trunk/mono/; revision=159863

mono/mini/ChangeLog
mono/mini/exceptions-arm.c
mono/mini/mini-arm.c
mono/mini/mini-arm.h
mono/mini/tramp-arm.c
mono/mini/unwind.c

index ac786bc34781eb3cbb8ded848e9314aa5a7f6da7..6217231c3d4b6d99fe88897a732860c8d06e9146 100755 (executable)
@@ -1,5 +1,14 @@
 2010-07-04  Zoltan Varga  <vargaz@gmail.com>
 
+       * unwind.c (decode_lsda): Use read32 for reading 32 bit quantities.
+
+       * tramp-arm.c (mono_arch_create_generic_trampoline): Save the original sp to
+       lmf->iregs [ARMREG_IP] to be consistent with mono_arch_emit_prolog ().
+
+       * mini-arm.h (MonoLMF): Remove unused fregs field, add comments for other fields.
+
+       * exceptions-arm.c: Clean up the handling of LMFs. Add LLVM exception trampolines.
+
        * mini-arm.c: Always use V5 for passing IMT/RGCTX when running under LLVM.
 
        * method-to-ir.c (emit_imt_argument): Fix LLVM support for architectures
index 99f4bcde25423419cd4b10b826b4ead191b802e0..7566f7ecb7bc0fcbc4bc215093aef1c9b56457ad 100644 (file)
@@ -165,6 +165,23 @@ mono_arm_throw_exception_by_token (guint32 type_token, unsigned long eip, unsign
        mono_arm_throw_exception ((MonoObject*)mono_exception_from_token (mono_defaults.corlib, type_token), eip, esp, int_regs, fp_regs);
 }
 
+static void
+mono_arm_resume_unwind (guint32 dummy1, unsigned long eip, unsigned long esp, gulong *int_regs, gdouble *fp_regs)
+{
+       MonoContext ctx;
+
+       eip &= ~1; /* clear the optional rethrow bit */
+       /* adjust eip so that it point into the call instruction */
+       eip -= 4;
+
+       MONO_CONTEXT_SET_BP (&ctx, int_regs [ARMREG_FP - 4]);
+       MONO_CONTEXT_SET_SP (&ctx, esp);
+       MONO_CONTEXT_SET_IP (&ctx, eip);
+       memcpy (((guint8*)&ctx.regs) + (4 * 4), int_regs, sizeof (gulong) * 8);
+
+       mono_resume_unwind (&ctx);
+}
+
 /**
  * get_throw_trampoline:
  *
@@ -175,7 +192,7 @@ mono_arm_throw_exception_by_token (guint32 type_token, unsigned long eip, unsign
  *
  */
 static gpointer 
-get_throw_trampoline (int size, gboolean corlib, gboolean rethrow, const char *tramp_name, MonoTrampInfo **info, gboolean aot)
+get_throw_trampoline (int size, gboolean corlib, gboolean rethrow, gboolean llvm, gboolean resume_unwind, const char *tramp_name, MonoTrampInfo **info, gboolean aot)
 {
        guint8 *start;
        guint8 *code;
@@ -199,6 +216,9 @@ get_throw_trampoline (int size, gboolean corlib, gboolean rethrow, const char *t
        /* exc is already in place in r0 */
        if (corlib) {
                /* The caller ip is already in R1 */
+               if (llvm)
+                       /* Negate the ip adjustment done in mono_arm_throw_exception */
+                       ARM_ADD_REG_IMM8 (code, ARMREG_R1, ARMREG_R1, 4);
        } else {
                ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_LR); /* caller ip */
        }
@@ -218,7 +238,7 @@ get_throw_trampoline (int size, gboolean corlib, gboolean rethrow, const char *t
                code += 4;
                ARM_LDR_REG_REG (code, ARMREG_IP, ARMREG_PC, ARMREG_IP);
        } else {
-               code = mono_arm_emit_load_imm (code, ARMREG_IP, GPOINTER_TO_UINT (corlib ? (gpointer)mono_arm_throw_exception_by_token : (gpointer)mono_arm_throw_exception));
+               code = mono_arm_emit_load_imm (code, ARMREG_IP, GPOINTER_TO_UINT (resume_unwind ? (gpointer)mono_arm_resume_unwind : (corlib ? (gpointer)mono_arm_throw_exception_by_token : (gpointer)mono_arm_throw_exception)));
        }
        ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
        ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
@@ -236,35 +256,35 @@ get_throw_trampoline (int size, gboolean corlib, gboolean rethrow, const char *t
 }
 
 /**
- * mono_arch_get_rethrow_exception:
+ * arch_get_throw_exception:
  *
- * Returns a function pointer which can be used to rethrow 
+ * Returns a function pointer which can be used to raise 
  * exceptions. The returned function has the following 
  * signature: void (*func) (MonoException *exc); 
+ * For example to raise an arithmetic exception you can use:
+ *
+ * x86_push_imm (code, mono_get_exception_arithmetic ()); 
+ * x86_call_code (code, arch_get_throw_exception ()); 
  *
  */
-gpointer
-mono_arch_get_rethrow_exception (MonoTrampInfo **info, gboolean aot)
+gpointer 
+mono_arch_get_throw_exception (MonoTrampInfo **info, gboolean aot)
 {
-       return get_throw_trampoline (132, FALSE, TRUE, "rethrow_exception", info, aot);
+       return get_throw_trampoline (132, FALSE, FALSE, FALSE, FALSE, "throw_exception", info, aot);
 }
 
 /**
- * arch_get_throw_exception:
+ * mono_arch_get_rethrow_exception:
  *
- * Returns a function pointer which can be used to raise 
+ * Returns a function pointer which can be used to rethrow 
  * exceptions. The returned function has the following 
  * signature: void (*func) (MonoException *exc); 
- * For example to raise an arithmetic exception you can use:
- *
- * x86_push_imm (code, mono_get_exception_arithmetic ()); 
- * x86_call_code (code, arch_get_throw_exception ()); 
  *
  */
-gpointer 
-mono_arch_get_throw_exception (MonoTrampInfo **info, gboolean aot)
+gpointer
+mono_arch_get_rethrow_exception (MonoTrampInfo **info, gboolean aot)
 {
-       return get_throw_trampoline (132, FALSE, FALSE, "throw_exception", info, aot);
+       return get_throw_trampoline (132, FALSE, TRUE, FALSE, FALSE, "rethrow_exception", info, aot);
 }
 
 /**
@@ -281,7 +301,7 @@ mono_arch_get_throw_exception (MonoTrampInfo **info, gboolean aot)
 gpointer 
 mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot)
 {
-       return get_throw_trampoline (168, TRUE, FALSE, "throw_corlib_exception", info, aot);
+       return get_throw_trampoline (168, TRUE, FALSE, FALSE, FALSE, "throw_corlib_exception", info, aot);
 }      
 
 void
@@ -292,16 +312,14 @@ mono_arch_exceptions_init (void)
        if (mono_aot_only) {
        } else {
                /* LLVM uses the normal trampolines, but with a different name */
-               tramp = get_throw_trampoline (168, TRUE, FALSE, "llvm_throw_corlib_exception", NULL, FALSE);
+               tramp = get_throw_trampoline (168, TRUE, FALSE, FALSE, FALSE, "llvm_throw_corlib_exception", NULL, FALSE);
                mono_register_jit_icall (tramp, "mono_arch_llvm_throw_corlib_exception", NULL, TRUE);
 
-               tramp = get_throw_trampoline (168, TRUE, FALSE, "llvm_throw_corlib_exception_abs", NULL, FALSE);
+               tramp = get_throw_trampoline (168, TRUE, FALSE, TRUE, FALSE, "llvm_throw_corlib_exception_abs", NULL, FALSE);
                mono_register_jit_icall (tramp, "mono_arch_llvm_throw_corlib_exception_abs", NULL, TRUE);
 
-               /*
-               tramp = get_throw_trampoline (NULL, FALSE, TRUE, TRUE, TRUE, "mono_llvm_resume_unwind_trampoline", FALSE);
+               tramp = get_throw_trampoline (168, FALSE, FALSE, FALSE, TRUE, "mono_llvm_resume_unwind_trampoline", NULL, FALSE);
                mono_register_jit_icall (tramp, "mono_llvm_resume_unwind_trampoline", NULL, TRUE);
-               */
        }
 }
 
@@ -353,9 +371,9 @@ mono_arch_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls,
                        new_ctx->regs [i] = regs [i];
                new_ctx->eip = regs [ARMREG_LR];
                new_ctx->esp = (gsize)cfa;
-               new_ctx->ebp = new_ctx->esp;
+               new_ctx->ebp = regs [ARMREG_FP];
 
-               if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
+               if (*lmf && (MONO_CONTEXT_GET_SP (ctx) >= (gpointer)(*lmf)->esp)) {
                        /* remove any unused lmf */
                        *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);
                }
@@ -394,13 +412,21 @@ mono_arch_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls,
                        frame->method = (*lmf)->method;
                }
 
+               /*
+                * The LMF is saved at the start of the method using:
+                * ARM_MOV_REG_REG (code, ARMREG_IP, ARMREG_SP)
+                * ARM_PUSH (code, 0x5ff0);
+                * So it stores the register state as it existed at the caller.
+                */
                memcpy (&new_ctx->regs [0], &(*lmf)->iregs [0], sizeof (gulong) * 13);
                /* SP is skipped */
                new_ctx->regs [ARMREG_LR] = (*lmf)->iregs [ARMREG_LR - 1];
-               /* This is the sp for the current frame */
-               new_ctx->esp = (*lmf)->iregs [ARMREG_FP];
-               new_ctx->eip = (*lmf)->iregs [13];
-               new_ctx->ebp = new_ctx->esp;
+               new_ctx->esp = (*lmf)->iregs [ARMREG_IP];
+               new_ctx->ebp = new_ctx->regs [ARMREG_FP];
+               new_ctx->eip = new_ctx->regs [ARMREG_LR];
+
+               /* we substract 1, so that the IP points into the call instruction */
+               new_ctx->eip--;
 
                *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);
 
index ebbe90ff8b1b62709c87d800a2734e8dc389df2b..8a69711a202da99699e5075bd816393c4bbdb234 100644 (file)
@@ -4768,7 +4768,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                /* *(lmf_addr) = r1 */
                ARM_STR_IMM (code, ARMREG_R1, ARMREG_R0, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
                /* Skip method (only needed for trampoline LMF frames) */
-               ARM_STR_IMM (code, ARMREG_SP, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, ebp));
+               ARM_STR_IMM (code, ARMREG_SP, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, esp));
                /* save the current IP */
                ARM_MOV_REG_REG (code, ARMREG_R2, ARMREG_PC);
                ARM_STR_IMM (code, ARMREG_R2, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, eip));
index eaff9887e52c6b8f10cfb03d79ace59ee4a3f154..b5a0935f2cc057a3b69f0fcd52cc4858e4f2b055 100644 (file)
@@ -99,13 +99,15 @@ struct MonoLMF {
         */
        gpointer    previous_lmf;
        gpointer    lmf_addr;
+       /* This is only set in trampoline LMF frames */
        MonoMethod *method;
        gulong     esp;
+       /* Unused */
        gulong     ebp;
        gulong     eip;
-       gdouble    fregs [MONO_SAVED_FREGS]; /* 8..15 */
        /* all but sp and pc: matches the PUSH instruction layout in the trampolines
         * 0-4 should be considered undefined (execpt in the magic tramp)
+        * sp is saved at IP.
         */
        gulong     iregs [14];
 };
index ffa84fd37bbab41a9692610ace7c07b929875d18..9d5b3467688c1126ef01e8bbd4aa1fd42fb373b5 100644 (file)
@@ -216,7 +216,10 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf
                ARM_MOV_REG_IMM8 (code, ARMREG_R2, 0);
                ARM_STR_IMM (code, ARMREG_R2, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, method));
        }
-       ARM_STR_IMM (code, ARMREG_SP, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, ebp));
+       /* Save sp into lmf->iregs, the eh code expects it to be at IP */
+       ARM_ADD_REG_IMM8 (code, ARMREG_R2, ARMREG_SP, cfa_offset);
+       ARM_STR_IMM (code, ARMREG_R2, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, iregs) + (ARMREG_IP * 4));
+       ARM_STR_IMM (code, ARMREG_SP, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, esp));
        /* save the IP (caller ip) */
        if (tramp_type == MONO_TRAMPOLINE_JUMP) {
                ARM_MOV_REG_IMM8 (code, ARMREG_R2, 0);
index 291b6ae8872c9d7d0d7dfe1ec9e7ae5fa41a63e1..f00a8a603c212ef98330b528aff6bb89e01d007e 100644 (file)
@@ -718,10 +718,12 @@ decode_lsda (guint8 *lsda, guint8 *code, MonoJitExceptionInfo **ex_info, guint32
        while (p < action_table) {
                int block_start_offset, block_size, landing_pad, action_offset;
 
-               block_start_offset = ((guint32*)p) [0];
-               block_size = ((guint32*)p) [1];
-               landing_pad = ((guint32*)p) [2];
-               p += 3 * sizeof (guint32);
+               block_start_offset = read32 (p);
+               p += sizeof (gint32);
+               block_size = read32 (p);
+               p += sizeof (gint32);
+               landing_pad = read32 (p);
+               p += sizeof (gint32);
                action_offset = decode_uleb128 (p, &p);
 
                /* landing_pad == 0 means the region has no landing pad */
@@ -743,10 +745,12 @@ decode_lsda (guint8 *lsda, guint8 *code, MonoJitExceptionInfo **ex_info, guint32
                int block_start_offset, block_size, landing_pad, action_offset, type_offset;
                guint8 *action, *tinfo;
 
-               block_start_offset = ((guint32*)p) [0];
-               block_size = ((guint32*)p) [1];
-               landing_pad = ((guint32*)p) [2];
-               p += 3 * sizeof (guint32);
+               block_start_offset = read32 (p);
+               p += sizeof (gint32);
+               block_size = read32 (p);
+               p += sizeof (gint32);
+               landing_pad = read32 (p);
+               p += sizeof (gint32);
                action_offset = decode_uleb128 (p, &p);
 
                action = action_table + action_offset - 1;
@@ -756,6 +760,8 @@ decode_lsda (guint8 *lsda, guint8 *code, MonoJitExceptionInfo **ex_info, guint32
                if (landing_pad) {
                        //printf ("BLOCK: %p-%p %p, %d\n", code + block_start_offset, code + block_start_offset + block_size, code + landing_pad, action_offset);
 
+                       g_assert (ttype_offset);
+
                        if (ttype_encoding == DW_EH_PE_absptr) {
                                guint8 *ttype_entry = (ttype - (type_offset * sizeof (gpointer)));
                                tinfo = *(gpointer*)ttype_entry;