changeset 9376:d58086453171

refactor unwind_protect
author Jaroslav Hajek <highegg@gmail.com>
date Tue, 23 Jun 2009 07:55:44 +0200
parents 14b1d3451858
children 610bf90fce2a
files src/ChangeLog src/pt-eval.cc src/unwind-prot.cc src/unwind-prot.h
diffstat 4 files changed, 172 insertions(+), 341 deletions(-) [+]
line wrap: on
line diff
--- a/src/ChangeLog	Mon Jun 22 21:00:18 2009 -0400
+++ b/src/ChangeLog	Tue Jun 23 07:55:44 2009 +0200
@@ -1,3 +1,12 @@
+2009-06-22  Jaroslav Hajek  <highegg@gmail.com>
+
+	* unwind-prot.h (unwind_protect): Rewrite.
+	(unwind_protect::protect_var): New class.
+	(unwind_protect::protect_mem): New class.
+	* unwind-prot.cc (unwind_protect): Rewrite.
+	* pt-eval.cc (tree_evaluator::visit_try_catch_command): Delete frame
+	properly.
+
 2009-06-22  Jaroslav Hajek  <highegg@gmail.com>
 
 	* ov-cell.cc (octave_cell::all_strings): Avoid duplicate conversions.
--- a/src/pt-eval.cc	Mon Jun 22 21:00:18 2009 -0400
+++ b/src/pt-eval.cc	Tue Jun 23 07:55:44 2009 +0200
@@ -900,7 +900,7 @@
       unwind_protect::run ();
 
       // Also clear the frame marker.
-      unwind_protect::discard ();
+      unwind_protect::run_frame ("tree_evaluator::visit_try_catch_command");
     }
 }
 
--- a/src/unwind-prot.cc	Mon Jun 22 21:00:18 2009 -0400
+++ b/src/unwind-prot.cc	Tue Jun 23 07:55:44 2009 +0200
@@ -2,6 +2,7 @@
 
 Copyright (C) 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2002, 2004,
               2005, 2006, 2007, 2008 John W. Eaton
+Copyright (C) 2009 VZLU Prague
 
 This file is part of Octave.
 
@@ -28,303 +29,58 @@
 #include <cstddef>
 #include <cstring>
 
-#include "CMatrix.h"
-
 #include "error.h"
 #include "unwind-prot.h"
 #include "utils.h"
 
-std::stack<unwind_elem> unwind_protect::elt_list;
-
-class
-saved_variable
-{
-public:
-
-  enum var_type
-  {
-    boolean,
-    integer,
-    size_type,
-    string_type,
-    generic_ptr,
-    generic
-  };
+std::stack<unwind_protect::elem> unwind_protect::elt_list;
 
-  saved_variable (void);
-
-  saved_variable (bool *p, bool v);
-
-  saved_variable (int *p, int v);
-
-  saved_variable (size_t *p, size_t v);
-
-  saved_variable (std::string *p, const std::string& v);
-
-  saved_variable (void **p, void *v);
-
-  ~saved_variable (void);
-
-  void restore_value (void);
-
-  static void restore (void *s);
-
-private:
+std::stack<std::pair <std::string, unwind_protect::frame_id_t> > unwind_protect::tag_list;
 
-  union
-    {
-      bool *ptr_to_bool;
-      int *ptr_to_int;
-      size_t *ptr_to_size_t;
-      void *gen_ptr;
-      void **ptr_to_gen_ptr;
-    };
-
-  union
-    {
-      bool bool_value;
-      int int_value;
-      size_t size_t_value;
-      std::string *str_value;
-      void *gen_ptr_value;
-    };
-
-  var_type type_tag;
-
-  size_t size;
-};
-
-saved_variable::saved_variable (void)
+unwind_protect::restore_mem::restore_mem (void *ptr, size_t size)
+  : rptr (ptr), sptr (reinterpret_cast<void *> (new char[size])), rsize (size)
 {
-  gen_ptr = 0;
-  gen_ptr_value = 0;
-  type_tag = generic;
-  size = 0;
-}
-
-saved_variable::saved_variable (bool *p, bool v)
-{
-  type_tag = boolean;
-  ptr_to_bool = p;
-  bool_value = v;
-  size = sizeof (bool);  // Is this necessary?
-}
-
-saved_variable::saved_variable (int *p, int v)
-{
-  type_tag = integer;
-  ptr_to_int = p;
-  int_value = v;
-  size = sizeof (int);  // Is this necessary?
-}
-
-saved_variable::saved_variable (size_t *p, size_t v)
-{
-  type_tag = size_type;
-  ptr_to_size_t = p;
-  size_t_value = v;
-  size = sizeof (size_t);  // Is this necessary?
+  std::memcpy (sptr, rptr, size);
 }
 
-saved_variable::saved_variable (std::string *p, const std::string& v)
-{
-  type_tag = string_type;
-  gen_ptr = p;
-  str_value = new std::string (v);
-  size = sizeof (std::string);  // Is this necessary?
-}
-
-saved_variable::saved_variable (void **p, void *v)
-{
-  type_tag = generic_ptr;
-  ptr_to_gen_ptr = p;
-  gen_ptr_value = v;
-  size = sizeof (void *);
-}
-
-saved_variable::~saved_variable (void)
-{
-  switch (type_tag)
-    {
-    case string_type:
-      delete str_value;
-      break;
-
-    case generic:
-      // FIXME
-      // delete [] gen_ptr_value;
-      break;
-
-    default:
-      break;
-    }
-}
-
-void
-saved_variable::restore_value (void)
+unwind_protect::restore_mem::~restore_mem (void)
 {
-  switch (type_tag)
-    {
-    case boolean:
-      *ptr_to_bool = bool_value;
-      break;
-
-    case integer:
-      *ptr_to_int = int_value;
-      break;
-
-    case size_type:
-      *ptr_to_size_t = size_t_value;
-      break;
-
-    case string_type:
-      (static_cast<std::string *> (gen_ptr)) -> assign (*str_value);
-      break;
-
-    case generic_ptr:
-      *ptr_to_gen_ptr = gen_ptr_value;
-      break;
-
-    case generic:
-      memcpy (gen_ptr, gen_ptr_value, size);
-      break;
-
-    default:
-      panic_impossible ();
-      break;
-    }
-}
-
-void
-saved_variable::restore (void *s)
-{
-  saved_variable *sv = static_cast<saved_variable *> (s);
-  sv->restore_value ();
-  delete sv;
-}
-
-void
-unwind_protect::add (unwind_elem::cleanup_func fptr, void *ptr)
-{
-  unwind_elem el (fptr, ptr);
-  elt_list.push (el);
-}
-
-void
-unwind_protect::run (void)
-{
-  unwind_elem el = elt_list.top ();
-
-  elt_list.pop ();
-
-  unwind_elem::cleanup_func f = el.fptr ();
-
-  if (f)
-    f (el.ptr ());
-}
-
-void
-unwind_protect::discard (void)
-{
-  elt_list.pop ();
+  std::memcpy (rptr, sptr, rsize);
+  delete [] reinterpret_cast<char *> (sptr);
 }
 
 void
 unwind_protect::begin_frame (const std::string& tag)
 {
-  unwind_elem elem (tag);
-  elt_list.push (elem);
+  tag_list.push (std::make_pair (tag, begin_frame ()));
 }
 
 void
 unwind_protect::run_frame (const std::string& tag)
 {
-  while (! elt_list.empty ())
+  while (! tag_list.empty ())
     {
-      unwind_elem el = elt_list.top ();
-
-      elt_list.pop ();
+      std::pair<std::string, frame_id_t> top = tag_list.top ();
+      tag_list.pop ();
 
-      unwind_elem::cleanup_func f = el.fptr ();
-
-      if (f)
-	f (el.ptr ());
-
-      if (tag == el.tag ())
-	break;
+      run_frame (top.second);
+      if (top.first == tag)
+        break;
     }
 }
 
 void
 unwind_protect::discard_frame (const std::string& tag)
 {
-  while (! elt_list.empty ())
-    {
-      unwind_elem el = elt_list.top ();
-
-      elt_list.pop ();
-
-      if (tag == el.tag ())
-	break;
-    }
-}
-
-void
-unwind_protect::run_all (void)
-{
-  while (! elt_list.empty ())
+  while (! tag_list.empty ())
     {
-      unwind_elem el = elt_list.top ();
-
-      elt_list.pop ();
-
-      unwind_elem::cleanup_func f = el.fptr ();
-
-      if (f)
-	f (el.ptr ());
-    }
-}
-
-void
-unwind_protect::discard_all (void)
-{
-  while (! elt_list.empty ())
-    elt_list.pop ();
-}
+      std::pair<std::string, frame_id_t> top = tag_list.top ();
+      tag_list.pop ();
 
-void
-unwind_protect::save_bool (bool *ptr, bool value)
-{
-  saved_variable *s = new saved_variable (ptr, value);
-  add (saved_variable::restore, s);
-}
-
-void
-unwind_protect::save_int (int *ptr, int value)
-{
-  saved_variable *s = new saved_variable (ptr, value);
-  add (saved_variable::restore, s);
-}
-
-void
-unwind_protect::save_size_t (size_t *ptr, size_t value)
-{
-  saved_variable *s = new saved_variable (ptr, value);
-  add (saved_variable::restore, s);
-}
-
-void
-unwind_protect::save_str (std::string *ptr, const std::string& value)
-{
-  saved_variable *s = new saved_variable (ptr, value);
-  add (saved_variable::restore, s);
-}
-
-void
-unwind_protect::save_ptr (void **ptr, void *value)
-{
-  saved_variable *s = new saved_variable (ptr, value);
-  add (saved_variable::restore, s);
+      run_frame (top.second);
+      if (top.first == tag)
+        break;
+    }
 }
 
 /*
--- a/src/unwind-prot.h	Mon Jun 22 21:00:18 2009 -0400
+++ b/src/unwind-prot.h	Tue Jun 23 07:55:44 2009 +0200
@@ -2,6 +2,7 @@
 
 Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 2000, 2002, 2004,
               2005, 2006, 2007, 2008 John W. Eaton
+Copyright (C) 2009 VZLU Prague
 
 This file is part of Octave.
 
@@ -28,52 +29,7 @@
 
 #include <string>
 #include <stack>
-
-class
-OCTINTERP_API
-unwind_elem
-{
-public:
-
-  typedef void (*cleanup_func) (void *ptr);
-
-  unwind_elem (void)
-    : ue_tag (), ue_fptr (0), ue_ptr (0) { }
-
-  unwind_elem (const std::string &t)
-    : ue_tag (t), ue_fptr (0), ue_ptr (0) { }
-
-  unwind_elem (cleanup_func f, void *p)
-    : ue_tag (), ue_fptr (f), ue_ptr (p) { }
-
-  unwind_elem (const unwind_elem& el)
-    : ue_tag (el.ue_tag), ue_fptr (el.ue_fptr), ue_ptr (el.ue_ptr) { }
-
-  ~unwind_elem (void) { }
-
-  unwind_elem& operator = (const unwind_elem& el)
-    {
-      ue_tag = el.ue_tag;
-      ue_fptr = el.ue_fptr;
-      ue_ptr = el.ue_ptr;
-
-      return *this;
-    }
-
-  std::string tag (void) { return ue_tag; }
-
-  cleanup_func fptr (void) { return ue_fptr; }
-
-  void *ptr (void) { return ue_ptr; }
-
-private:
-
-  std::string ue_tag;
-
-  cleanup_func ue_fptr;
-
-  void *ue_ptr;
-};
+#include <utility>
 
 class
 OCTINTERP_API
@@ -81,64 +37,174 @@
 {
 public:
 
-  static void add (unwind_elem::cleanup_func fptr, void *ptr = 0);
+  // This template class can be used to restore value of a variable of any
+  // class posessing a copy constructor and assignment operator.
 
-  static void run (void);
+  template <class T>
+  class
+  restore_var
+  {
+  public:
+    restore_var (T *ptr, const T& val) 
+      : rptr (ptr), rval(val) { }
+    restore_var (T *ptr) 
+      : rptr (ptr), rval(*ptr) { }
+    ~restore_var (void)
+      { *rptr = rval; }
 
-  static void discard (void);
+    // For unwind_protect.
+    static void cleanup (void *ptr)
+      {
+        delete reinterpret_cast<restore_var *> (ptr);
+      }
+
+  private:
 
-  static void begin_frame (const std::string& tag);
+    // No copying!
+    void operator = (const restore_var&); 
+
+    T *rptr, rval;
+  };
+
+  // This class is used to restore arbitrary memory area using std::memcpy.
 
-  static void run_frame (const std::string& tag);
+  class
+  restore_mem
+  {
+  public:
+    restore_mem (void *ptr, size_t size);
+    ~restore_mem (void);
 
-  static void discard_frame (const std::string& tag);
+    // For unwind_protect.
+    static void cleanup (void *ptr)
+      {
+        delete reinterpret_cast<restore_mem *> (ptr);
+      }
+
+  private:
+
+    // No copying!
+    void operator = (const restore_mem&); 
 
-  static void run_all (void);
+    void *rptr, *sptr;
+    size_t rsize;
+  };
+
+  typedef void (*cleanup_func) (void *ptr);
+
+  typedef size_t frame_id_t;
+
+  typedef std::pair<cleanup_func, void *> elem;
 
-  static void discard_all (void);
+  static bool empty (void)
+    { return elt_list.empty (); }
+
+  static void add (cleanup_func fptr, void *ptr = 0)
+    {
+      elt_list.push (elem (fptr, ptr));
+    }
+
+  static void run (void)
+    {
+      elem elt = elt_list.top ();
+      elt_list.pop ();
 
-  // Ways to save variables.
+      elt.first (elt.second);
+    }
 
-  static void save_bool (bool *ptr, bool value);
+  static void discard (void)
+    {
+      elt_list.pop ();
+    }
+
+  static frame_id_t begin_frame ()
+    {
+      return elt_list.size ();
+    }
 
-  static void save_int (int *ptr, int value);
+  static void run_frame (frame_id_t frame_id)
+    {
+      while (elt_list.size () > frame_id)
+        run ();
+    }
 
-  static void save_size_t (size_t *ptr, size_t value);
+  static void discard_frame (frame_id_t frame_id)
+    {
+      while (elt_list.size () > frame_id)
+        discard ();
+    }
+
+  // String tags are deprecated. Use the above trio.
+
+  static void begin_frame (const std::string& tag) GCC_ATTR_DEPRECATED;
+
+  static void run_frame (const std::string& tag) GCC_ATTR_DEPRECATED;
+
+  static void discard_frame (const std::string& tag) GCC_ATTR_DEPRECATED;
 
-  static void save_str (std::string *ptr, const std::string& value);
+  static void run_all (void)
+    { 
+      run_frame (0);
+      while (! tag_list.empty ())
+        tag_list.pop ();
+    }
 
-  static void save_ptr (void **ptr, void *value);
+  static void discard_all (void)
+    { 
+      discard_frame (0);
+      while (! tag_list.empty ())
+        tag_list.pop ();
+    }
 
-  static void save_var (void *ptr, void *value, size_t size);
+  // Protect any variable.
+  template <class T>
+  static void protect_var (T& var)
+    {
+      add (restore_var<T>::cleanup, new restore_var<T> (&var));
+    }
 
-  static std::stack<unwind_elem> elt_list;
+  // Protect any variable, value given.
+  template <class T>
+  static void protect_var (T& var, const T& val)
+    {
+      add (restore_var<T>::cleanup, new restore_var<T> (&var, val));
+    }
+
+  // Protect an area of memory.
+  static void protect_mem (void *ptr, size_t size)
+    {
+      add (restore_mem::cleanup, new restore_mem (ptr, size));
+    }
+
+private:
+
+  static std::stack<elem> elt_list;
+
+  static std::stack<std::pair <std::string, frame_id_t> > tag_list;
 };
 
-// We could get by without these macros, but they are nice to have...
+// Backward compatibility macros. Avoid them; use protect_var directly.
 
 #define unwind_protect_bool(b) \
-  unwind_protect::save_bool (&(b), (b))
+  unwind_protect::protect_var (b)
 
 #define unwind_protect_int(i) \
-  unwind_protect::save_int (&(i), (i))
+  unwind_protect::protect_var (i)
 
 #define unwind_protect_size_t(i) \
-  unwind_protect::save_size_t (&(i), (i))
+  unwind_protect::protect_var (i)
 
 #define unwind_protect_str(s) \
-  unwind_protect::save_str (&(s), (s))
+  unwind_protect::protect_var (s)
 
 #define unwind_protect_ptr(p) \
-  unwind_protect::save_ptr (reinterpret_cast<void **> (&(p)), \
-                            reinterpret_cast<void *> (p))
+  unwind_protect::protect_var (p)
 
 #define unwind_protect_fptr(p) \
-  unwind_protect::save_ptr (reinterpret_cast<void **> (&(p)), \
-                            FCN_PTR_CAST (void *, p))
+  unwind_protect::protect_var (p)
 
 #define unwind_protect_const_ptr(p) \
-  unwind_protect::save_ptr (const_cast<void **> (reinterpret_cast<const void **> (&(p))), \
-                            const_cast<void *> (reinterpret_cast<const void *> (p)))
+  unwind_protect::protect_var (p)
 
 #endif