changeset 32441:030cf510f141

Lookup function cache with arguments on the bytecode vm stack Avoids allocating container for bytecode to bytecode calls by using pointers to the vm stack as parameters to function cache querries. * ov-base.h: New function get_cached_fcn(void*,void*) * ov-fcn-handle.cc: get_cached_fcn(void*,void*) * ov-fcn-handle.h: get_cached_fcn(void*,void*) * ov-fcn.h: New functions get_cached_fcn_if_fresh, has_cached_function, get_cached_fcn(void*,void*) * ov-fcn.cc: Defs * ov.h: New function get_cached_fcn(void*,void*)
author Petter T.
date Fri, 27 Oct 2023 18:19:39 +0200
parents b36ac2c31cb2
children c841a01aca55
files libinterp/octave-value/ov-base.h libinterp/octave-value/ov-fcn-handle.cc libinterp/octave-value/ov-fcn-handle.h libinterp/octave-value/ov-fcn.cc libinterp/octave-value/ov-fcn.h libinterp/octave-value/ov.h
diffstat 6 files changed, 130 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/octave-value/ov-base.h	Fri Oct 27 18:19:32 2023 +0200
+++ b/libinterp/octave-value/ov-base.h	Fri Oct 27 18:19:39 2023 +0200
@@ -551,6 +551,8 @@
 
   virtual octave_function * get_cached_fcn (const octave_value_list&) { return nullptr; }
 
+  virtual octave_function * get_cached_fcn (void*, void*) { return nullptr; }
+
   virtual octave_fcn_cache * fcn_cache_value (void) { return nullptr; }
 
   virtual void erase_subfunctions () { }
--- a/libinterp/octave-value/ov-fcn-handle.cc	Fri Oct 27 18:19:32 2023 +0200
+++ b/libinterp/octave-value/ov-fcn-handle.cc	Fri Oct 27 18:19:39 2023 +0200
@@ -233,6 +233,9 @@
   octave_function *
   get_cached_fcn (const octave_value_list &args);
 
+  octave_function *
+  get_cached_fcn (void *beg, void *end);
+
   bool has_function_cache (void) const;
 
 private:
@@ -311,6 +314,15 @@
   friend bool is_equal_to (const scoped_fcn_handle& fh1,
                            const scoped_fcn_handle& fh2);
 
+  octave_function *
+  get_cached_fcn (void *, void *) { return m_fcn.function_value (); }
+
+  octave_function *
+  get_cached_fcn (const octave_value_list&) { return m_fcn.function_value (); }
+
+  bool
+  has_function_cache (void) const { return true; }
+
 protected:
 
   void find_function ();
@@ -697,6 +709,10 @@
 
   octave_function *
   get_cached_fcn (const octave_value_list&) { return m_fcn.function_value (); }
+
+  octave_function *
+  get_cached_fcn (void *, void *) { return m_fcn.function_value (); }
+
   // TODO: This is a hack to get uncompiled anonymous functions to be subsrefed in the VM
   bool has_function_cache (void) const
   {
@@ -977,6 +993,7 @@
 
 // FIXME: Find a way to avoid duplication of code in
 // simple_fcn_handle::call
+
 octave_function *
 simple_fcn_handle::
 get_cached_fcn (const octave_value_list &args)
@@ -1033,6 +1050,23 @@
   }
 }
 
+octave_function *
+simple_fcn_handle::
+get_cached_fcn (void *pbeg, void *pend)
+{
+  if (m_cache.has_cached_function (pbeg, pend))
+    return m_cache.get_cached_fcn ();
+
+  octave::stack_element *beg = static_cast<octave::stack_element *> (pbeg);
+  octave::stack_element *end = static_cast<octave::stack_element *> (pend);
+
+  octave_value_list args;
+  while (beg != end)
+    args.append ((beg++)->ov);
+
+  return get_cached_fcn (args); // TODO: Avoid extra call to has_cached_function()
+}
+
 // FIXME: Find a way to avoid duplication of code in
 // simple_fcn_handle::call
 // Like call(), but instead returns true if the call() would end
--- a/libinterp/octave-value/ov-fcn-handle.h	Fri Oct 27 18:19:32 2023 +0200
+++ b/libinterp/octave-value/ov-fcn-handle.h	Fri Oct 27 18:19:39 2023 +0200
@@ -155,7 +155,11 @@
   }
 
   virtual octave_function *
+  get_cached_fcn (void *, void *) { return nullptr; }
+
+  virtual octave_function *
   get_cached_fcn (const octave_value_list&) { return nullptr; }
+
   virtual bool
   has_function_cache (void) const { return false; }
 
@@ -374,7 +378,11 @@
   is_equal_to (const octave_fcn_handle& fh1, const octave_fcn_handle& fh2);
 
   octave_function *
+  get_cached_fcn (void *beg, void *end) { return m_rep->get_cached_fcn (beg, end); }
+
+  octave_function *
   get_cached_fcn (const octave_value_list& args) { return m_rep->get_cached_fcn (args); }
+
   bool has_function_cache (void) const { return m_rep->has_function_cache (); }
 
   vm_call_dispatch_type vm_dispatch_call (void)
--- a/libinterp/octave-value/ov-fcn.cc	Fri Oct 27 18:19:32 2023 +0200
+++ b/libinterp/octave-value/ov-fcn.cc	Fri Oct 27 18:19:39 2023 +0200
@@ -69,6 +69,29 @@
   return execute (tw, nargout, args);
 }
 
+bool
+octave_fcn_cache::has_cached_function (void *pbeg, void *pend) const
+{
+  octave::stack_element *beg = static_cast<octave::stack_element *> (pbeg);
+  octave::stack_element *end = static_cast<octave::stack_element *> (pend);
+
+  if (m_n_updated == 0)
+    return false;
+
+  unsigned vec_n = m_cached_args.size ();
+
+  unsigned n_args = end - beg;
+  if (n_args != vec_n)
+    return false;
+
+  for (unsigned i = 0; i < n_args; i++)
+    {
+      if (beg[i].ov.type_id () != m_cached_args [i])
+        return false;
+    }
+
+  return true;
+}
 
 void
 octave_fcn_cache::set_cached_function (octave_value ov,
@@ -79,6 +102,9 @@
 
   if (!ov.is_defined ())
     return;
+  // Arbitrary limit on how many args we keep track of in caches.
+  if (args.length () > 32)
+    return;
 
   // We need to keep a reference to the metaobject for as long as the function is alive
   if (ov.is_classdef_meta ())
@@ -105,12 +131,12 @@
 
 octave_value
 octave_fcn_cache::
-get_cached_obj (const octave_value_list& args)
+get_cached_obj ()
 {
   octave_function *fcn = nullptr;
 
   octave_idx_type current_n_updated = octave::load_path::get_weak_n_updated ();
-  if (has_cached_function (args))
+  if (has_cached_function (nullptr, nullptr))
     {
       if (m_n_updated == current_n_updated)
         return m_cached_function;
@@ -124,12 +150,12 @@
         octave::__get_interpreter__ ();
 
       octave::symbol_table& symtab = interp.get_symbol_table ();
-      octave_value val = symtab.find_function (m_fcn_name, args);
+      octave_value val = symtab.find_function (m_fcn_name, octave_value_list {});
 
       if (val.is_function ())
         {
           fcn = val.function_value (true);
-          set_cached_function (val, args, current_n_updated);
+          set_cached_function (val, octave_value_list {}, current_n_updated);
           return val;
         }
 
@@ -176,6 +202,16 @@
 
 octave_function *
 octave_fcn_cache::
+get_cached_fcn_if_fresh ()
+{
+  octave_idx_type current_n_updated = octave::load_path::get_weak_n_updated ();
+  if (m_n_updated == current_n_updated)
+    return get_cached_fcn ();
+  return nullptr;
+}
+
+octave_function *
+octave_fcn_cache::
 get_cached_fcn (const octave_value_list& args)
 {
   octave_idx_type current_n_updated = octave::load_path::get_weak_n_updated ();
@@ -186,6 +222,30 @@
   return get_cached_fcn_internal (args);
 }
 
+octave_function *
+octave_fcn_cache::
+get_cached_fcn (void *pbeg, void *pend)
+{
+  octave_idx_type current_n_updated = octave::load_path::get_weak_n_updated ();
+  if (OCTAVE_LIKELY (has_cached_function (pbeg, pend)))
+    if (OCTAVE_LIKELY (m_n_updated == current_n_updated))
+      return m_cached_function.function_value (true);
+
+  octave::stack_element *beg = static_cast<octave::stack_element *> (pbeg);
+  octave::stack_element *end = static_cast<octave::stack_element *> (pend);
+
+  octave_value_list args;
+  for (; beg != end; beg++)
+    {
+      if (OCTAVE_UNLIKELY (beg->ov.is_cs_list ()))
+        args.append (beg->ov.list_value ());
+      else
+        args.append (beg->ov);
+    }
+
+  return get_cached_fcn_internal (args);
+}
+
 octave_value_list
 octave_fcn_cache::
 call (octave::tree_evaluator& tw,
--- a/libinterp/octave-value/ov-fcn.h	Fri Oct 27 18:19:32 2023 +0200
+++ b/libinterp/octave-value/ov-fcn.h	Fri Oct 27 18:19:39 2023 +0200
@@ -71,10 +71,13 @@
   get_cached_fcn (const octave_value_list& args);
 
   octave_function *
+  get_cached_fcn (void *beg, void *end);
+
+  octave_function *
   get_cached_fcn () { return m_cached_function.function_value (); }
 
   octave_value
-  get_cached_obj (const octave_value_list& args);
+  get_cached_obj ();
 
   octave_fcn_cache * fcn_cache_value (void)
   {
@@ -109,6 +112,10 @@
     return true;
   }
 
+  bool has_cached_function (void *beg, void *end) const;
+
+  octave_function * get_cached_fcn_if_fresh ();
+
 private:
 
   octave_function * get_cached_fcn_internal (const octave_value_list& args);
@@ -318,6 +325,15 @@
            const octave_value_list& args = octave_value_list ()) = 0;
 
   vm_call_dispatch_type vm_dispatch_call (void) { return vm_call_dispatch_type::CALL; }
+
+  octave_function *
+  get_cached_fcn (void *, void *) { return function_value (); }
+
+  octave_function *
+  get_cached_fcn (const octave_value_list&) { return function_value (); }
+
+  bool has_function_cache (void) const { return true; }
+
 protected:
 
   octave_function (const std::string& nm,
--- a/libinterp/octave-value/ov.h	Fri Oct 27 18:19:32 2023 +0200
+++ b/libinterp/octave-value/ov.h	Fri Oct 27 18:19:39 2023 +0200
@@ -1572,6 +1572,11 @@
   octave_function * get_cached_fcn (const octave_value_list& args)
   { return m_rep->get_cached_fcn (args); }
 
+  // Arguments need to be pointing to union stack_element:s.
+  // Using void* to avoid polluting namespace.
+  octave_function * get_cached_fcn (void *beg, void *end)
+  { return m_rep->get_cached_fcn (beg, end); }
+
   // Returns true if the octave_value is either undefined or
   // or a function.
   bool is_maybe_function (void) const