changeset 32307:02faaad763d4

VM Add support for echo Introcudes flag in tree_evaluator that can be checked to see if echo, debug, VM profiler is enabled. * libinterp/corefcn/compile.cc: Notify tree_evalutor VM profiler is active * libinterp/parse-tree/pt-bytecode-vm.cc: Support echo, check new flag dbgprofecho * libinterp/parse-tree/pt-bytecode-vm.h: New flag * libinterp/parse-tree/pt-bytecode-walk.cc: 'Is script' flag for unwind data * libinterp/parse-tree/pt-bytecode.h: * libinterp/parse-tree/pt-eval.cc: Set dbgprofecho flag. Expose echo state to VM. * libinterp/parse-tree/pt-eval.h:
author Petter T.
date Mon, 07 Aug 2023 10:10:49 +0200
parents 56acd8f390f8
children d8311055ebe1
files libinterp/corefcn/compile.cc libinterp/parse-tree/pt-bytecode-vm.cc libinterp/parse-tree/pt-bytecode-vm.h libinterp/parse-tree/pt-bytecode-walk.cc libinterp/parse-tree/pt-bytecode.h libinterp/parse-tree/pt-eval.cc libinterp/parse-tree/pt-eval.h
diffstat 7 files changed, 138 insertions(+), 39 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/compile.cc	Sat Aug 19 13:05:33 2023 +0200
+++ b/libinterp/corefcn/compile.cc	Mon Aug 07 10:10:49 2023 +0200
@@ -189,12 +189,7 @@
 {
   int nargin = args.length ();
 
-  // Unless a "profiler enabled" flag is added to the evaluator
-  // the vm profiler need the debugger to be active for it to actually
-  // be able to profile.
-  if (!interp.get_evaluator ().debug_mode ())
-    warning ("As a workaround atleast one breakpoint has to be set"
-    " in any file (preferably not being profiled) for the profiler to actually profile anything.");
+  auto &evaler = interp.get_evaluator ();
 
   std::string arg0;
 
@@ -208,9 +203,11 @@
           vm::m_vm_profiler = std::make_shared<vm_profiler> ();
 
           vm::m_profiler_enabled = true;
+          evaler.vm_set_profiler_active (true);
         }
       else
         {
+          evaler.vm_set_profiler_active (false);
           vm::m_profiler_enabled = false;
           auto p = vm::m_vm_profiler;
           vm::m_vm_profiler = nullptr;
@@ -224,6 +221,7 @@
       vm::m_profiler_enabled = false;
       vm::m_vm_profiler = std::make_shared<vm_profiler> ();
       vm::m_profiler_enabled = true;
+      evaler.vm_set_profiler_active (true);
     }
   else if (arg0 == "resume")
     {
@@ -231,13 +229,16 @@
         vm::m_vm_profiler = std::make_shared<vm_profiler> ();
 
       vm::m_profiler_enabled = true;
+      evaler.vm_set_profiler_active (true);
     }
   else if (arg0 == "off")
     {
+      evaler.vm_set_profiler_active (false);
       vm::m_profiler_enabled = false;
     }
   else if (arg0 == "clear")
     {
+      evaler.vm_set_profiler_active (false);
       vm::m_profiler_enabled = false;
       vm::m_vm_profiler = nullptr;
     }
--- a/libinterp/parse-tree/pt-bytecode-vm.cc	Sat Aug 19 13:05:33 2023 +0200
+++ b/libinterp/parse-tree/pt-bytecode-vm.cc	Mon Aug 07 10:10:49 2023 +0200
@@ -642,7 +642,7 @@
   /* PRINT_VM_STATE ("%d" COMMA __LINE__); */ \
   /* CHECK_STACK (0); */ \
 \
-  if (OCTAVE_UNLIKELY (m_tw->debug_mode ())) /* Do we need to check for breakpoints? */\
+  if (OCTAVE_UNLIKELY (m_tw->vm_dbgprofecho_flag ())) /* Do we need to check for breakpoints? */\
     goto debug_check;\
   int opcode = ip[0];\
   arg0 = ip[1];\
@@ -659,7 +659,7 @@
   /* PRINT_VM_STATE ("%d" COMMA __LINE__); */ \
   /* CHECK_STACK (0); */ \
 \
-  if (OCTAVE_UNLIKELY (m_tw->debug_mode ())) /* Do we need to check for breakpoints? */\
+  if (OCTAVE_UNLIKELY (m_tw->vm_dbgprofecho_flag ())) /* Do we need to check for breakpoints? */\
     goto debug_check_1b;\
   int opcode = arg0;\
   arg0 = *ip++;\
@@ -4344,6 +4344,8 @@
     m_ip = ip - code;
     m_unwind_data = unwind_data;
 
+    m_echo_prior_op_was_cond = false; // Used by the echo functionality
+
     // Ther error_type is put on the stack before the jump to unwind.
     error_type et = static_cast<error_type> (m_sp[-1].i);
     m_sp--;
@@ -5674,6 +5676,7 @@
         PRINT_VM_STATE ("Trace: ");
       }
 
+    // Handle the VM profiler
     if (OCTAVE_UNLIKELY (m_profiler_enabled))
       {
         int64_t t1 = vm_profiler::unow ();
@@ -5702,43 +5705,97 @@
           }
       }
 
+    // Handle the echo functionality.
+    if (m_tw->echo ())
+      {
+        int ip_offset = ip - code;
+        // In the beginning of functions we need to push an echo state for the function.
+        // push_echo_state () checks e.g. if the current function is supposed to be printed.
+        // The check is querried with echo_state ().
+        if (ip_offset == 4) // TODO: Make constexpr for first opcode offset
+          {
+            int type = m_unwind_data->m_is_script ? tree_evaluator::ECHO_SCRIPTS : tree_evaluator::ECHO_FUNCTIONS;
+            m_tw->push_echo_state (type, m_unwind_data->m_file);
+          }
+
+        if (!m_tw->echo_state ())
+          goto bail_echo;
+
+        auto it = unwind_data->m_ip_to_tree.find (tmp_ip);
+        if (it == unwind_data->m_ip_to_tree.end ())
+          goto bail_echo;
+
+        tree *t = it->second;
+        if (!t)
+          goto bail_echo;
+
+        int line = t->line ();
+        if (line < 0)
+          line = 1;
+
+        // We don't want to echo the condition checks in for loops, but
+        // reset the "last echoed" line to echo the next line properly.
+        switch (static_cast<INSTR> (*ip))
+          {
+            case INSTR::FOR_COND:
+            case INSTR::FOR_COMPLEX_COND:
+              m_echo_prior_op_was_cond = true;
+              goto bail_echo;
+            default:
+              break;
+          }
+
+        if (m_echo_prior_op_was_cond)
+          {
+            m_echo_prior_op_was_cond = false;
+            m_tw->set_echo_file_pos (line);
+          }
+
+        m_tw->echo_code (line);
+        m_tw->set_echo_file_pos (line + 1);
+      }
+bail_echo:
+
     // TODO: Check all trees one time and cache the result somewhere?
     //       Until another bp is set? Debugging will be quite slow
     //       with one check for each op-code.
 
-    auto it = unwind_data->m_ip_to_tree.find (tmp_ip);
-
-    if (it == unwind_data->m_ip_to_tree.end ())
-      goto debug_check_end;
-
-    bool is_ret = *ip == static_cast<unsigned char> (INSTR::RET);
-
-    m_sp = sp;
-    m_bsp = bsp;
-    m_rsp = rsp;
-    m_code = code;
-    m_data = data;
-    m_name_data = name_data;
-    m_ip = tmp_ip;
-    m_unwind_data = unwind_data;
-    m_tw->set_active_bytecode_ip (tmp_ip);
-
-    tree *t = it->second;
-
-    // do_breakpoint will check if there is a breakpoint attached
-    // to the relevant code and escape to the debugger repl
-    // if neccessary.
-    if (t)
-      {
-        try
+    if (m_tw->debug_mode ())
+      {
+        auto it = unwind_data->m_ip_to_tree.find (tmp_ip);
+
+        if (it == unwind_data->m_ip_to_tree.end ())
+          goto debug_check_end;
+
+        bool is_ret = *ip == static_cast<unsigned char> (INSTR::RET);
+
+        m_sp = sp;
+        m_bsp = bsp;
+        m_rsp = rsp;
+        m_code = code;
+        m_data = data;
+        m_name_data = name_data;
+        m_ip = tmp_ip;
+        m_unwind_data = unwind_data;
+        m_tw->set_active_bytecode_ip (tmp_ip);
+
+        tree *t = it->second;
+
+        // do_breakpoint will check if there is a breakpoint attached
+        // to the relevant code and escape to the debugger repl
+        // if neccessary.
+        if (t)
           {
-            m_tw->do_breakpoint (t->is_active_breakpoint (*m_tw), is_ret);
+            try
+              {
+                m_tw->do_breakpoint (t->is_active_breakpoint (*m_tw), is_ret);
+              }
+            CATCH_INTERRUPT_EXCEPTION
+            CATCH_INDEX_EXCEPTION
+            CATCH_EXECUTION_EXCEPTION
+            CATCH_BAD_ALLOC
+            CATCH_EXIT_EXCEPTION
           }
-        CATCH_INTERRUPT_EXCEPTION
-        CATCH_INDEX_EXCEPTION
-        CATCH_EXECUTION_EXCEPTION
-        CATCH_BAD_ALLOC
-        CATCH_EXIT_EXCEPTION
       }
   }
   debug_check_end:
--- a/libinterp/parse-tree/pt-bytecode-vm.h	Sat Aug 19 13:05:33 2023 +0200
+++ b/libinterp/parse-tree/pt-bytecode-vm.h	Mon Aug 07 10:10:49 2023 +0200
@@ -522,6 +522,8 @@
   std::string *m_name_data;
   unwind_data *m_unwind_data;
 
+  bool m_echo_prior_op_was_cond = false;
+
   int m_ip;
 
   // Generic data container to recreate exceptions
--- a/libinterp/parse-tree/pt-bytecode-walk.cc	Sat Aug 19 13:05:33 2023 +0200
+++ b/libinterp/parse-tree/pt-bytecode-walk.cc	Mon Aug 07 10:10:49 2023 +0200
@@ -2040,6 +2040,7 @@
 {
   m_is_script = true;
 
+  m_code.m_unwind_data.m_is_script = true;
   m_code.m_unwind_data.m_name = fcn.name ();
   m_code.m_unwind_data.m_file = fcn.fcn_file_name ();
   PUSH_DATA (fcn.name ());
--- a/libinterp/parse-tree/pt-bytecode.h	Sat Aug 19 13:05:33 2023 +0200
+++ b/libinterp/parse-tree/pt-bytecode.h	Mon Aug 07 10:10:49 2023 +0200
@@ -233,6 +233,8 @@
 
   unsigned m_code_size;
   unsigned m_ids_size;
+
+  bool m_is_script;
 };
 
 struct bytecode
--- a/libinterp/parse-tree/pt-eval.cc	Sat Aug 19 13:05:33 2023 +0200
+++ b/libinterp/parse-tree/pt-eval.cc	Mon Aug 07 10:10:49 2023 +0200
@@ -1367,12 +1367,15 @@
                   || m_dbstep_flag != 0
                   || m_break_on_next_stmt
                   || in_debug_repl ());
+
+  update_vm_dbgprofecho_flag ();
 }
 
 void
 tree_evaluator::reset_debug_state (bool mode)
 {
   m_debug_mode = mode;
+  update_vm_dbgprofecho_flag ();
 }
 
 void
@@ -4850,6 +4853,7 @@
                                 int pos)
 {
   m_echo_state = echo_this_file (file_name, type);
+
   m_echo_file_name = file_name;
   m_echo_file_pos = pos;
 }
@@ -4859,6 +4863,7 @@
                                     int pos)
 {
   m_echo_state = state;
+
   m_echo_file_name = file_name;
   m_echo_file_pos = pos;
 }
@@ -5040,6 +5045,8 @@
   if (cleanup_pushed)
     maybe_set_echo_state ();
 
+  update_vm_dbgprofecho_flag (); // Since m_echo might have changed value we need to call this
+
   return octave_value ();
 }
 
--- a/libinterp/parse-tree/pt-eval.h	Sat Aug 19 13:05:33 2023 +0200
+++ b/libinterp/parse-tree/pt-eval.h	Mon Aug 07 10:10:49 2023 +0200
@@ -838,6 +838,8 @@
   {
     int old_val = m_echo;
     m_echo = val;
+
+    update_vm_dbgprofecho_flag ();
     return old_val;
   }
 
@@ -858,6 +860,21 @@
 
   bool debug_mode () const { return m_debug_mode; }
 
+  int echo_state () { return m_echo_state; }
+
+  void set_echo_file_pos (int pos)
+  {
+    m_echo_file_pos = pos;
+  }
+
+  void vm_set_profiler_active (bool val)
+  {
+    m_vm_profiler_active = val;
+    update_vm_dbgprofecho_flag ();
+  }
+
+  bool vm_dbgprofecho_flag () { return m_vm_dbg_profile_echo; }
+
 private:
 
   template <typename T>
@@ -973,6 +990,18 @@
 
   std::string m_echo_file_name;
 
+  // The VM needs to keep know if the evaluation is in a debug, echo or profiler
+  // state.
+  bool m_vm_dbg_profile_echo; // Set to true if either echo, dbg or vm profiler active
+  bool m_vm_profiler_active; // VM specific profiler flag
+
+  // Set m_vm_dbg_profile_echo to its proper state. Need to be done after each update to
+  // the underlying flags.
+  void update_vm_dbgprofecho_flag ()
+  {
+    m_vm_dbg_profile_echo = m_debug_mode || m_echo || m_vm_profiler_active;
+  }
+
   // Next line to echo, counting from 1.  We use int here because the
   // parser does.  It also initializes line and column numbers to the
   // invalid value -1 and that can cause trouble if cast to an