From 81461c26b7e40e7c27804407571199a5247815d4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mattias=20Engdeg=C3=A5rd?= <mattiase@acm.org>
Date: Tue, 2 May 2023 16:23:11 +0200
Subject: [PATCH 2/2] Make regexp cache size adjustable at run-time

---
 src/alloc.c  |  2 ++
 src/lisp.h   |  1 +
 src/search.c | 85 +++++++++++++++++++++++++++++++++++++++-------------
 3 files changed, 67 insertions(+), 21 deletions(-)

diff --git a/src/alloc.c b/src/alloc.c
index d09fc41dec6..0b11b5469a9 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -6451,6 +6451,8 @@ garbage_collect (void)
   mark_terminals ();
   mark_kboards ();
   mark_threads ();
+  mark_regexp_cache ();
+
 #ifdef HAVE_PGTK
   mark_pgtkterm ();
 #endif
diff --git a/src/lisp.h b/src/lisp.h
index ab66109d5df..8b2beadefd6 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -4745,6 +4745,7 @@ XMODULE_FUNCTION (Lisp_Object o)
 extern void syms_of_fileio (void);
 
 /* Defined in search.c.  */
+extern void mark_regexp_cache (void);
 extern void shrink_regexp_cache (void);
 extern void restore_search_regs (void);
 extern void update_search_regs (ptrdiff_t oldstart,
diff --git a/src/search.c b/src/search.c
index 6f71f3d16c1..c454d5e1ca9 100644
--- a/src/search.c
+++ b/src/search.c
@@ -34,7 +34,7 @@ Copyright (C) 1985-1987, 1993-1994, 1997-1999, 2001-2023 Free Software
 
 #include "regex-emacs.h"
 
-#define REGEXP_CACHE_SIZE 20
+#define DEFAULT_REGEXP_CACHE_SIZE 20
 
 /* If the regexp is non-nil, then the buffer contains the compiled form
    of that regexp, suitable for searching.  */
@@ -55,7 +55,9 @@ #define REGEXP_CACHE_SIZE 20
 };
 
 /* The instances of that struct.  */
-static struct regexp_cache searchbufs[REGEXP_CACHE_SIZE];
+static struct regexp_cache *searchbufs;
+/* Allocated size of searchbufs array, in elements.  */
+static int regexp_cache_size = 0;
 
 /* The head of the linked list; points to the most recently used buffer.  */
 static struct regexp_cache *searchbuf_head;
@@ -158,7 +160,7 @@ clear_regexp_cache (void)
 {
   int i;
 
-  for (i = 0; i < REGEXP_CACHE_SIZE; ++i)
+  for (i = 0; i < regexp_cache_size; ++i)
     /* It's tempting to compare with the syntax-table we've actually changed,
        but it's not sufficient because char-table inheritance means that
        modifying one syntax-table can change others at the same time.  */
@@ -3376,18 +3378,68 @@ DEFUN ("newline-cache-check", Fnewline_cache_check, Snewline_cache_check,
 }
 
 
-static void syms_of_search_for_pdumper (void);
+static void
+set_regexp_cache_size (int n)
+{
+  for (int i = 0; i < regexp_cache_size; i++)
+    xfree (searchbufs[i].buf.buffer);
+
+  size_t bytes = n * sizeof *searchbufs;
+  searchbufs = xrealloc (searchbufs, bytes);
+  memset (searchbufs, 0, bytes);
+  regexp_cache_size = n;
+
+  for (int i = 0; i < n; i++)
+    {
+      searchbufs[i].buf.allocated = 100;
+      searchbufs[i].buf.buffer = xmalloc (100);
+      searchbufs[i].buf.fastmap = searchbufs[i].fastmap;
+      searchbufs[i].regexp = Qnil;
+      searchbufs[i].f_whitespace_regexp = Qnil;
+      searchbufs[i].busy = false;
+      searchbufs[i].syntax_table = Qnil;
+      searchbufs[i].next = (i == regexp_cache_size-1 ? 0 : &searchbufs[i+1]);
+    }
+  searchbuf_head = &searchbufs[0];
+}
+
+DEFUN ("regexp-cache-size", Fregexp_cache_size, Sregexp_cache_size,
+       0, 0, 0,
+       doc: /* Current regexp cache size.  Internal use only.  */)
+  (void)
+{
+  return make_int (regexp_cache_size);
+}
+
+DEFUN ("set-regexp-cache-size", Fset_regexp_cache_size, Sset_regexp_cache_size,
+       1, 1, 0,
+       doc: /* Set the regexp cache size to N elements.  Internal use only.  */)
+  (Lisp_Object n)
+{
+  CHECK_FIXNUM (n);
+  EMACS_INT nelems = XFIXNUM (n);
+  if (nelems <= 0)
+    error ("regexp cache size must be positive");
+  set_regexp_cache_size (nelems);
+  return Qnil;
+}
 
 void
-syms_of_search (void)
+mark_regexp_cache (void)
 {
-  for (int i = 0; i < REGEXP_CACHE_SIZE; ++i)
+  for (int i = 0; i < regexp_cache_size; ++i)
     {
-      staticpro (&searchbufs[i].regexp);
-      staticpro (&searchbufs[i].f_whitespace_regexp);
-      staticpro (&searchbufs[i].syntax_table);
+      mark_object (searchbufs[i].regexp);
+      mark_object (searchbufs[i].f_whitespace_regexp);
+      mark_object (searchbufs[i].syntax_table);
     }
+}
 
+static void syms_of_search_for_pdumper (void);
+
+void
+syms_of_search (void)
+{
   /* Error condition used for failing searches.  */
   DEFSYM (Qsearch_failed, "search-failed");
 
@@ -3460,6 +3512,8 @@ syms_of_search (void)
   defsubr (&Smatch_data__translate);
   defsubr (&Sregexp_quote);
   defsubr (&Snewline_cache_check);
+  defsubr (&Sregexp_cache_size);
+  defsubr (&Sset_regexp_cache_size);
 
   pdumper_do_now_and_after_load (syms_of_search_for_pdumper);
 }
@@ -3467,16 +3521,5 @@ syms_of_search (void)
 static void
 syms_of_search_for_pdumper (void)
 {
-  for (int i = 0; i < REGEXP_CACHE_SIZE; ++i)
-    {
-      searchbufs[i].buf.allocated = 100;
-      searchbufs[i].buf.buffer = xmalloc (100);
-      searchbufs[i].buf.fastmap = searchbufs[i].fastmap;
-      searchbufs[i].regexp = Qnil;
-      searchbufs[i].f_whitespace_regexp = Qnil;
-      searchbufs[i].busy = false;
-      searchbufs[i].syntax_table = Qnil;
-      searchbufs[i].next = (i == REGEXP_CACHE_SIZE-1 ? 0 : &searchbufs[i+1]);
-    }
-  searchbuf_head = &searchbufs[0];
+  set_regexp_cache_size (DEFAULT_REGEXP_CACHE_SIZE);
 }
-- 
2.32.0 (Apple Git-132)

