# HG changeset patch
# User Petter T. <petter.vilhelm@gmail.com>
# Date 1703281809 -3600
#      Fri Dec 22 22:50:09 2023 +0100
# Branch bytecode-interpreter
# Node ID 6ff28bc97530dec9a6b23fdfa14242a8cb809532
# Parent  70ecd191a2aa2893e42b29c809f0b1eb54583d0c
Handle quit_debug_exception in bytecode interpreter (bug #65056)

To allow for escaping debugging in gui properly.

* pt-bytecode-vm.cc: Catch quit_debug_exception, handle in unwind
* pt-bytecode-vm.h: New field 'm_debug_quit_all'
* pt-bytecode.h: New 'DEBUG_QUIT' error type
* pt-eval.cc: Move quit_debug_exception def to header
* pt-eval.h

diff -r 70ecd191a2aa -r 6ff28bc97530 libinterp/parse-tree/pt-bytecode-vm.cc
--- a/libinterp/parse-tree/pt-bytecode-vm.cc	Fri Dec 22 22:51:52 2023 +0100
+++ b/libinterp/parse-tree/pt-bytecode-vm.cc	Fri Dec 22 22:50:09 2023 +0100
@@ -4916,14 +4916,17 @@
     // Save current exception to the error system in handle_error ()
     error_data errdat = handle_error (et);
 
-    // Only run unwind_protect code if the exception is the interrupt or OOM exception.
+    // Run only unwind_protect code if the exception is the interrupt exception.
     // I.e. no 'throw ... catch' code.
     bool only_unwind_protect = et == error_type::INTERRUPT_EXC;
 
     while (1)
       {
-        // Find unwind entry for current value of the instruction pointer
-        unwind_entry *entry = find_unwind_entry_for_current_state (only_unwind_protect);
+        // Find unwind entry for current value of the instruction pointer, unless we are dealing
+        // with a debug quit exception in which case no unwind entry is used.
+        unwind_entry *entry = nullptr;
+        if (et != error_type::DEBUG_QUIT)
+          entry = find_unwind_entry_for_current_state (only_unwind_protect);
 
         unwind_entry_type type = unwind_entry_type::INVALID;
         if (entry)
@@ -5078,6 +5081,8 @@
     // Rethrow exceptions out of the VM
     if (et == error_type::INTERRUPT_EXC)
       throw interrupt_exception {};
+    else if (et == error_type::DEBUG_QUIT)
+      throw quit_debug_exception {errdat.m_debug_quit_all};
     else if (et == error_type::EXIT_EXCEPTION)
       throw exit_exception (errdat.m_exit_status, errdat.m_safe_to_return);
     else
@@ -6494,6 +6499,12 @@
             CATCH_EXECUTION_EXCEPTION
             CATCH_BAD_ALLOC
             CATCH_EXIT_EXCEPTION
+            catch (const quit_debug_exception &qde)
+              {
+                (*sp++).i = qde.all ();
+                (*sp++).i = static_cast<int>(error_type::DEBUG_QUIT);
+                goto unwind;
+              }
           }
       }
   }
@@ -7214,6 +7225,13 @@
 
       break;
     }
+    case error_type::DEBUG_QUIT:
+    {
+      ret.m_debug_quit_all = m_sp[-1].i;
+      m_sp--;
+
+      break;
+    }
     default:
       TODO ("Unhandeled error type");
     }
@@ -8317,8 +8335,15 @@
 
     tw.pop_stack_frame ();
     throw;
+  } catch (const quit_debug_exception &qde) {
+    if (vm.m_dbg_proper_return == false)
+      panic ("quit debug exception escaping the vm");
+
+    tw.pop_stack_frame ();
+    throw;
   }
 
+
   tw.pop_stack_frame ();
   return ret;
 }
diff -r 70ecd191a2aa -r 6ff28bc97530 libinterp/parse-tree/pt-bytecode-vm.h
--- a/libinterp/parse-tree/pt-bytecode-vm.h	Fri Dec 22 22:51:52 2023 +0100
+++ b/libinterp/parse-tree/pt-bytecode-vm.h	Fri Dec 22 22:50:09 2023 +0100
@@ -589,6 +589,8 @@
     // Execution exception
     int m_exit_status;
     bool m_safe_to_return;
+    // Debug quit
+    bool m_debug_quit_all;
   };
 
   error_data
diff -r 70ecd191a2aa -r 6ff28bc97530 libinterp/parse-tree/pt-bytecode.h
--- a/libinterp/parse-tree/pt-bytecode.h	Fri Dec 22 22:51:52 2023 +0100
+++ b/libinterp/parse-tree/pt-bytecode.h	Fri Dec 22 22:50:09 2023 +0100
@@ -347,6 +347,7 @@
   RHS_UNDEF_IN_ASSIGNMENT,
   BAD_ALLOC,
   EXIT_EXCEPTION,
+  DEBUG_QUIT,
 };
 
 enum class global_type
diff -r 70ecd191a2aa -r 6ff28bc97530 libinterp/parse-tree/pt-eval.cc
--- a/libinterp/parse-tree/pt-eval.cc	Fri Dec 22 22:51:52 2023 +0100
+++ b/libinterp/parse-tree/pt-eval.cc	Fri Dec 22 22:50:09 2023 +0100
@@ -81,25 +81,6 @@
 
 // Normal evaluator.
 
-class quit_debug_exception
-{
-public:
-
-  quit_debug_exception (bool all = false) : m_all (all) { }
-
-  quit_debug_exception (const quit_debug_exception&) = default;
-
-  quit_debug_exception& operator = (const quit_debug_exception&) = default;
-
-  ~quit_debug_exception () = default;
-
-  bool all () const { return m_all; }
-
-private:
-
-  bool m_all;
-};
-
 class debugger
 {
 public:
diff -r 70ecd191a2aa -r 6ff28bc97530 libinterp/parse-tree/pt-eval.h
--- a/libinterp/parse-tree/pt-eval.h	Fri Dec 22 22:51:52 2023 +0100
+++ b/libinterp/parse-tree/pt-eval.h	Fri Dec 22 22:50:09 2023 +0100
@@ -1063,6 +1063,25 @@
   int m_num_indices;
 };
 
+class quit_debug_exception
+{
+public:
+
+  quit_debug_exception (bool all = false) : m_all (all) { }
+
+  quit_debug_exception (const quit_debug_exception&) = default;
+
+  quit_debug_exception& operator = (const quit_debug_exception&) = default;
+
+  ~quit_debug_exception () = default;
+
+  bool all () const { return m_all; }
+
+private:
+
+  bool m_all;
+};
+
 OCTAVE_END_NAMESPACE(octave)
 
 #endif
