# HG changeset patch
# User Petter Tomner <tomner@kth.se>
# Date 1640119834 -3600
#      Tue Dec 21 21:50:34 2021 +0100
# Node ID 1145def305ec82f6c21212c2614929845fa7b530
# Parent  ab40600a7cb0bdba00fbb6cd4174fa64b5217fcd
interpreter: Object pool for octave_lvalue

Use an object pool for allocating octave_lvalues

libinterp/parse-tree
	* oct-lvalue.cc: Use object pool
	* oct-lvalue.h

diff -r ab40600a7cb0 -r 1145def305ec libinterp/parse-tree/oct-lvalue.cc
--- a/libinterp/parse-tree/oct-lvalue.cc	Mon Dec 13 02:02:08 2021 +0100
+++ b/libinterp/parse-tree/oct-lvalue.cc	Tue Dec 21 21:50:34 2021 +0100
@@ -207,4 +207,36 @@
 
     return retval;
   }
+
+  thread_local octave_lvalue_idx::object_pool_cleaner
+  octave_lvalue_idx::pool_cleaner __attribute__ ((tls_model ("initial-exec")));
+
+  octave_lvalue_idx::object_pool_cleaner *dummy_idx =
+    &octave_lvalue_idx::pool_cleaner;
+
+  thread_local octave_lvalue_id::object_pool_cleaner
+  octave_lvalue_id::pool_cleaner __attribute__ ((tls_model ("initial-exec")));
+
+  octave_lvalue_id::object_pool_cleaner *dummy_id =
+    &octave_lvalue_id::pool_cleaner;
+
+  thread_local octave_lvalue_blackhole::object_pool_cleaner
+  octave_lvalue_blackhole::pool_cleaner __attribute__ ((tls_model ("initial-exec")));
+
+  octave_lvalue_blackhole::object_pool_cleaner *dummy_bh =
+    &octave_lvalue_blackhole::pool_cleaner;
+
+  thread_local int octave_lvalue_idx::n_in_obj_pool
+  __attribute__ ((tls_model ("initial-exec")));
+  thread_local int octave_lvalue_id::n_in_obj_pool
+  __attribute__ ((tls_model ("initial-exec")));
+    thread_local int octave_lvalue_blackhole::n_in_obj_pool
+  __attribute__ ((tls_model ("initial-exec")));
+
+  thread_local void * octave_lvalue_idx::obj_pool[obj_pool_size]
+    __attribute__ ((tls_model ("initial-exec")));
+  thread_local void * octave_lvalue_id::obj_pool[obj_pool_size]
+    __attribute__ ((tls_model ("initial-exec")));
+  thread_local void * octave_lvalue_blackhole::obj_pool[obj_pool_size]
+    __attribute__ ((tls_model ("initial-exec")));
 }
diff -r ab40600a7cb0 -r 1145def305ec libinterp/parse-tree/oct-lvalue.h
--- a/libinterp/parse-tree/oct-lvalue.h	Mon Dec 13 02:02:08 2021 +0100
+++ b/libinterp/parse-tree/oct-lvalue.h	Tue Dec 21 21:50:34 2021 +0100
@@ -99,6 +99,28 @@
   class octave_lvalue_idx : public octave_lvalue_base
   {
   public:
+
+    // Overloaded new and delete operators that uses a object pool.
+    static void * operator new (std::size_t count)
+    {
+      // If n_in_obj_pool is negative, the pool is closed
+      if (n_in_obj_pool > 0)
+        return obj_pool[--n_in_obj_pool];
+
+      return ::operator new (count);
+    }
+
+    static void operator delete (void* ptr)
+    {
+      // If n_in_obj_pool is negative, the pool is closed
+      if (n_in_obj_pool >= 0 && n_in_obj_pool < obj_pool_size)
+        {
+          obj_pool[n_in_obj_pool++] = ptr;
+          return;
+        }
+      ::operator delete (ptr);
+    }
+
     octave_lvalue_idx (const symbol_record& sr,
                        const std::shared_ptr<stack_frame>& frame,
                        const std::string &type,
@@ -156,6 +178,28 @@
       return new octave_lvalue_idx (m_sym, m_frame, m_type, m_idx);
     }
 
+    // Class that cleans the object pool when the thread terminates
+    class object_pool_cleaner
+    {
+    public:
+      ~object_pool_cleaner()
+      {
+        int n = n_in_obj_pool;
+        // Set the counter to -1 so that any lingering objects
+        // do use the pool
+        n_in_obj_pool = -1;
+
+        for (int i = 0; i < n; i++)
+          octave_lvalue_idx::operator delete (obj_pool[i]);
+      }
+    };
+
+    // For work around reasons pool_cleaner can't be private. Its addres
+    // has to be taken somewhere to fool the compiler to trigger its
+    // destructor.
+    thread_local static object_pool_cleaner pool_cleaner
+    __attribute__ ((tls_model ("initial-exec")));
+
   private:
 
     octave_value
@@ -167,11 +211,42 @@
     std::list<octave_value_list> m_idx;
 
     octave_idx_type m_nel;
+
+    static constexpr int obj_pool_size = 8;
+
+    // Counter for amount of objects in the pool
+    thread_local static int  n_in_obj_pool
+    __attribute__ ((tls_model ("initial-exec")));
+    // The pool
+    thread_local static void * obj_pool[obj_pool_size]
+    __attribute__ ((tls_model ("initial-exec")));
   };
 
   class octave_lvalue_id : public octave_lvalue_base
   {
   public:
+
+    // Overloaded new and delete operators that uses a object pool.
+    static void * operator new (std::size_t count)
+    {
+      // If n_in_obj_pool is negative, the pool is closed
+      if (n_in_obj_pool > 0)
+        return obj_pool[--n_in_obj_pool];
+
+      return ::operator new (count);
+    }
+
+    static void operator delete (void* ptr)
+    {
+      // If n_in_obj_pool is negative, the pool is closed
+      if (n_in_obj_pool >= 0 && n_in_obj_pool < obj_pool_size)
+        {
+          obj_pool[n_in_obj_pool++] = ptr;
+          return;
+        }
+      ::operator delete (ptr);
+    }
+
     octave_lvalue_id (const symbol_record& sr,
                       const std::shared_ptr<stack_frame>& frame)
       : octave_lvalue_base (sr, frame) { }
@@ -212,11 +287,65 @@
                                     std::move (m_frame),
                                     type, idx);
     }
+
+    // Class that cleans the object pool when the thread terminates
+    class object_pool_cleaner
+    {
+    public:
+      ~object_pool_cleaner()
+      {
+        int n = n_in_obj_pool;
+        // Set the counter to -1 so that any lingering objects
+        // do use the pool
+        n_in_obj_pool = -1;
+
+        for (int i = 0; i < n; i++)
+          octave_lvalue_id::operator delete (obj_pool[i]);
+      }
+    };
+
+    // For work around reasons pool_cleaner can't be private. Its addres
+    // has to be taken somewhere to fool the compiler to trigger its
+    // destructor.
+    thread_local static object_pool_cleaner pool_cleaner
+    __attribute__ ((tls_model ("initial-exec")));
+
+  private:
+    static constexpr int obj_pool_size = 8;
+
+    // Counter for amount of objects in the pool
+    thread_local static int  n_in_obj_pool
+    __attribute__ ((tls_model ("initial-exec")));
+    // The pool
+    thread_local static void * obj_pool[obj_pool_size]
+    __attribute__ ((tls_model ("initial-exec")));
   };
 
   class octave_lvalue_blackhole : public octave_lvalue_base
   {
   public:
+
+    // Overloaded new and delete operators that uses a object pool.
+    static void * operator new (std::size_t count)
+    {
+      // If n_in_obj_pool is negative, the pool is closed
+      if (n_in_obj_pool > 0)
+        return obj_pool[--n_in_obj_pool];
+
+      return ::operator new (count);
+    }
+
+    static void operator delete (void* ptr)
+    {
+      // If n_in_obj_pool is negative, the pool is closed
+      if (n_in_obj_pool >= 0 && n_in_obj_pool < obj_pool_size)
+        {
+          obj_pool[n_in_obj_pool++] = ptr;
+          return;
+        }
+      ::operator delete (ptr);
+    }
+
     octave_lvalue_blackhole (const symbol_record& sr,
                              const std::shared_ptr<stack_frame>& frame)
       : octave_lvalue_base (sr, frame) { }
@@ -245,6 +374,38 @@
       error ("can't set index on black hole");
       return nullptr; // Unreachable
     }
+
+    // Class that cleans the object pool when the thread terminates
+    class object_pool_cleaner
+    {
+    public:
+      ~object_pool_cleaner()
+      {
+        int n = n_in_obj_pool;
+        // Set the counter to -1 so that any lingering objects
+        // do use the pool
+        n_in_obj_pool = -1;
+
+        for (int i = 0; i < n; i++)
+          octave_lvalue_blackhole::operator delete (obj_pool[i]);
+      }
+    };
+
+    // For work around reasons pool_cleaner can't be private. Its addres
+    // has to be taken somewhere to fool the compiler to trigger its
+    // destructor.
+    thread_local static object_pool_cleaner pool_cleaner
+    __attribute__ ((tls_model ("initial-exec")));
+
+  private:
+    static constexpr int obj_pool_size = 8;
+
+    // Counter for amount of objects in the pool
+    thread_local static int  n_in_obj_pool
+    __attribute__ ((tls_model ("initial-exec")));
+    // The pool
+    thread_local static void * obj_pool[obj_pool_size]
+    __attribute__ ((tls_model ("initial-exec")));
   };
 
   class octave_lvalue
@@ -363,7 +524,6 @@
 
     // Only for builder functions
     octave_lvalue (octave_lvalue_base *rep) : m_rep (rep) { };
-
   };
 }
 
