svm: Fix continue_from_trap.
authorMatt Birkholz <puck@birchwood-abbey.net>
Fri, 10 Oct 2014 23:57:02 +0000 (16:57 -0700)
committerMatt Birkholz <puck@birchwood-abbey.net>
Fri, 10 Oct 2014 23:57:02 +0000 (16:57 -0700)
Signal handlers always find an unknown pc when the svm interpreter is
running.  This patch extracts the virtual machine's instruction
pointer for classify_pc in the hope that the compiled code block can
be located.

src/microcode/cmpintmd/svm1.h
src/microcode/svm1-interp.c
src/microcode/uxtrap.c

index 021a675555a51644457063a6078461262ffa77e6..e2625420828bd455346bb5db0523a04304818f94 100644 (file)
@@ -93,5 +93,6 @@ extern long C_to_interface (void *);
 extern void initialize_svm1 (void);
 extern insn_t * read_uuo_target (SCHEME_OBJECT *);
 extern unsigned int read_u16 (insn_t *);
+extern unsigned long svm_export_instruction_pointer (unsigned long pc);
 
 #endif /* !SCM_CMPINTMD_H_INCLUDED */
index 7a87732de938e5ed341baa05224ae2f4f7d216c7..08bf0eb801282852c362cafb83b4f9e929cc4c28 100644 (file)
@@ -212,20 +212,43 @@ initialize_svm1 (void)
   SET_VAL ((SCHEME_OBJECT) (WREG_REF (SVM1_REG_VALUE)));               \
 } while (0)
 
+/* Only true when the virtual machine is running, e.g. while Free is
+   cached in word_registers[].  In a signal handler, the virtual
+   instruction that trapped is at instruction_pointer. */
+static bool running_p = false;
+static insn_t * instruction_pointer;
+
 long
 C_to_interface (void * address)
 {
-  insn_t * PC = (insn_t *)address;
+  instruction_pointer = (insn_t *)address;
   IMPORT_REGS ();
-  while (predict_true (PC))
+  running_p = true;
+  while (predict_true (instruction_pointer))
     {
-      byte_t opcode = *PC++;
-      PC = (* (inst_defns[opcode])) (PC);
+      byte_t opcode = *instruction_pointer;
+      instruction_pointer = (* (inst_defns[opcode])) (instruction_pointer+1);
     }
   EXPORT_REGS ();
+  running_p = false;
   return (svm1_result);
 }
 
+/* For signal/trap handlers. */
+unsigned long
+svm_export_instruction_pointer (unsigned long pc)
+{
+  if (running_p)
+    {
+      EXPORT_REGS ();
+      return ((unsigned long)instruction_pointer);
+    }
+  else
+    {
+      return (pc);
+    }
+}
+
 static byte_t *
 illegal_instruction (byte_t * PC)
 {
@@ -848,10 +871,12 @@ illegal_trap_3 (byte_t * PC, wreg_t r1, wreg_t r2, wreg_t r3)
 
 #define TRAP_PREFIX(result)                                            \
   utility_result_t result;                                             \
-  EXPORT_REGS ()
+  EXPORT_REGS ();                                                      \
+  running_p = false
 
 #define TRAP_SUFFIX(result)                                            \
   IMPORT_REGS ();                                                      \
+  running_p = true;                                                    \
   if ((result).scheme_p)                                               \
     {                                                                  \
       NEW_PC ((result).arg.new_pc);                                    \
index 6e7db83ba3d2fa343bf34b8cf8d5b8e10d79201c..a2ac2936e29120cd607ed4d25ffd876f7fccd668 100644 (file)
@@ -353,6 +353,9 @@ continue_from_trap (int signo, SIGINFO_T info, SIGCONTEXT_T * scp)
 #ifdef PC_VALUE_MASK
   pc &= PC_VALUE_MASK;
 #endif
+#ifdef CC_IS_SVM
+  pc = svm_export_instruction_pointer (pc);
+#endif
 
   /* Choose new SP and encode location data.  */
   switch (classify_pc (pc, (&block_addr), (&index)))
@@ -366,8 +369,15 @@ continue_from_trap (int signo, SIGINFO_T info, SIGCONTEXT_T * scp)
     case pcl_heap:
     case pcl_constant:
 #ifdef CC_SUPPORT_P
+
+#  ifdef CC_IS_SVM
+      new_sp = stack_pointer;
+      /* Free already set by svm_export_instruction_pointer. */
+#  else
       new_sp = ((SCHEME_OBJECT *) (SIGCONTEXT_SCHSP (scp)));
       Free = ((SCHEME_OBJECT *) (SIGCONTEXT_RFREE (scp)));
+#  endif
+
       SET_RECOVERY_INFO
        (STATE_COMPILED_CODE,
         (MAKE_CC_BLOCK (block_addr)),