changeset 23729:06b3d1d54054

allow echo state to be modified from inside functions * ov-usr-fcn.h, ov-usr-fcn.cc (octave_user_code::curr_unwind_protect_frame, octave_user_code::unwind_protect_frame): Move variable and accessor function here from octave_user_function. (octave_user_script::call): Also unwind-protect and set current unwind_protect frame variable here. * pt-eval.h, pt-eval.cc (tree_evaluator::set_echo_state, tree_evaluator::maybe_set_echo_state, tree_evaluator::push_echo_state_cleanup, maybe_push_echo_state_cleanup): New functions. (tree_evaluator::push_echo_state): Call push_ech_state_cleanup and set_echo_state. (tree_evaluator::echo): Call maybe_push_echo_state_cleanup and set_echo_state.
author John W. Eaton <jwe@octave.org>
date Wed, 05 Jul 2017 08:37:45 -0400
parents b40b7243a782
children 85f1d31956c0
files libinterp/octave-value/ov-usr-fcn.cc libinterp/octave-value/ov-usr-fcn.h libinterp/parse-tree/pt-eval.cc libinterp/parse-tree/pt-eval.h
diffstat 4 files changed, 91 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/octave-value/ov-usr-fcn.cc	Wed Jul 05 09:44:01 2017 -0400
+++ b/libinterp/octave-value/ov-usr-fcn.cc	Wed Jul 05 08:37:45 2017 -0400
@@ -157,6 +157,12 @@
 
       cs.push (this);
 
+      // Set pointer to the current unwind_protect frame to allow
+      // certain builtins register simple cleanup in a very optimized manner.
+      // This is *not* intended as a general-purpose on-cleanup mechanism,
+      frame.protect_var (curr_unwind_protect_frame);
+      curr_unwind_protect_frame = &frame;
+
       frame.add_method (cs, &octave::call_stack::pop);
 
       // Update line number even if debugging.
@@ -214,7 +220,7 @@
     subfunction (false), inline_function (false),
     anonymous_function (false), nested_function (false),
     class_constructor (none), class_method (false),
-    parent_scope (0), curr_unwind_protect_frame (0)
+    parent_scope (0)
 #if defined (HAVE_LLVM)
     , jit_info (0)
 #endif
--- a/libinterp/octave-value/ov-usr-fcn.h	Wed Jul 05 09:44:01 2017 -0400
+++ b/libinterp/octave-value/ov-usr-fcn.h	Wed Jul 05 08:37:45 2017 -0400
@@ -91,7 +91,6 @@
 
   std::deque<std::string> get_code_lines (size_t line, size_t num_lines);
 
-
   virtual std::map<std::string, octave_value> subfunctions (void) const;
 
   virtual octave::tree_statement_list * body (void) = 0;
@@ -388,12 +387,6 @@
 
   void accept (octave::tree_walker& tw);
 
-  octave::unwind_protect *
-  unwind_protect_frame (void)
-  {
-    return curr_unwind_protect_frame;
-  }
-
 #if defined (HAVE_LLVM)
   jit_function_info * get_info (void) { return jit_info; }
 
@@ -487,9 +480,6 @@
   // The scope of the parent function, if any.
   octave::symbol_table::scope *parent_scope;
 
-  // pointer to the current unwind_protect frame of this function.
-  octave::unwind_protect *curr_unwind_protect_frame;
-
 #if defined (HAVE_LLVM)
   jit_function_info *jit_info;
 #endif
--- a/libinterp/parse-tree/pt-eval.cc	Wed Jul 05 09:44:01 2017 -0400
+++ b/libinterp/parse-tree/pt-eval.cc	Wed Jul 05 08:37:45 2017 -0400
@@ -2843,9 +2843,53 @@
                                   "silent_functions");
   }
 
+  octave_value
+  tree_evaluator::string_fill_char (const octave_value_list& args, int nargout)
+  {
+    return set_internal_variable (m_string_fill_char, args, nargout,
+                                  "string_fill_char");
+  }
+
   void
   tree_evaluator::push_echo_state (unwind_protect& frame, int type,
-                                   const std::string& file_name)
+                                   const std::string& file_name,
+                                   size_t pos)
+  {
+    push_echo_state_cleanup (frame);
+
+    set_echo_state (type, file_name, pos);
+  }
+
+  void
+  tree_evaluator::set_echo_state (int type, const std::string& file_name,
+                                  size_t pos)
+  {
+    m_echo_state = echo_this_file (file_name, type);
+    m_echo_file_name = file_name;
+    m_echo_file_pos = pos;
+  }
+
+  void
+  tree_evaluator::maybe_set_echo_state (void)
+  {
+    octave_function *caller = m_call_stack.caller ();
+
+    if (caller && caller->is_user_code ())
+      {
+        octave_user_code *fcn = dynamic_cast<octave_user_code *> (caller);
+
+        int type = fcn->is_user_function () ? ECHO_FUNCTIONS : ECHO_SCRIPTS;
+
+        std::string file_name = fcn->fcn_file_name ();
+
+        size_t pos = m_call_stack.current_line ();
+
+        set_echo_state (type, file_name, pos);
+      }
+  }
+
+  void
+  tree_evaluator::push_echo_state_cleanup (unwind_protect& frame)
   {
     frame.add_method (*this, &tree_evaluator::set_echo_state,
                       m_echo_state);
@@ -2855,22 +2899,39 @@
 
     frame.add_method (*this, &tree_evaluator::set_echo_file_pos,
                       m_echo_file_pos);
-
-    m_echo_state = echo_this_file (file_name, type);
-    m_echo_file_name = file_name;
-    m_echo_file_pos = 1;
   }
 
-  octave_value
-  tree_evaluator::string_fill_char (const octave_value_list& args, int nargout)
+  bool tree_evaluator::maybe_push_echo_state_cleanup (void)
   {
-    return set_internal_variable (m_string_fill_char, args, nargout,
-                                  "string_fill_char");
+    // This function is expected to be called from ECHO, which would be
+    // the top of the call stack.  If the caller of ECHO is a
+    // user-defined fucntion or script, then set up unwind-protect
+    // elements to restore echo state.
+
+    octave_function *caller = m_call_stack.caller ();
+
+    if (caller && caller->is_user_code ())
+      {
+        octave_user_code *fcn = dynamic_cast<octave_user_code *> (caller);
+
+        unwind_protect *frame = fcn->unwind_protect_frame ();
+
+        if (frame)
+          {
+            push_echo_state_cleanup (*frame);
+            return true;
+          }
+      }
+
+    return false;
   }
 
+
   octave_value
   tree_evaluator::echo (const octave_value_list& args, int)
   {
+    bool cleanup_pushed = maybe_push_echo_state_cleanup ();
+
     string_vector argv = args.make_argv ();
 
     switch (args.length ())
@@ -2988,6 +3049,9 @@
         break;
       }
 
+    if (cleanup_pushed)
+      maybe_set_echo_state ();
+
     return ovl ();
   }
 
--- a/libinterp/parse-tree/pt-eval.h	Wed Jul 05 09:44:01 2017 -0400
+++ b/libinterp/parse-tree/pt-eval.h	Wed Jul 05 08:37:45 2017 -0400
@@ -365,14 +365,22 @@
       return old_val;
     }
 
-    void push_echo_state (unwind_protect& frame, int type,
-                          const std::string& file_name);
-
     octave_value
     string_fill_char (const octave_value_list& args, int nargout);
 
+    void push_echo_state (unwind_protect& frame, int type,
+                          const std::string& file_name, size_t pos = 1);
+
   private:
 
+    void set_echo_state (int type, const std::string& file_name, size_t pos);
+
+    void maybe_set_echo_state (void);
+
+    void push_echo_state_cleanup (unwind_protect& frame);
+
+    bool maybe_push_echo_state_cleanup (void);
+
     void do_breakpoint (tree_statement& stmt) const;
 
     void do_breakpoint (bool is_breakpoint,