I encountered an m4 program that performed over 20 million iterations
of a tail-call recursion paradigm.  Without this patch, memory usage
grew to over 6 gigabytes, pausing the program for several seconds when
the recursion finally ended just to reclaim the memory.  But with the
patch, m4 never needed more than 3 megabytes of resident memory.

* src/input.c (push_string_init): Prune empty string blocks before
starting another one.
---
 src/input.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/src/input.c b/src/input.c
index 23d200bd..f8f57234 100644
--- a/src/input.c
+++ b/src/input.c
@@ -165,6 +165,9 @@ static struct re_registers regs;
 #ifdef DEBUG_INPUT
 static const char *token_type_string (token_type);
 #endif
+
+static void pop_input (void);
+
 

 /*-------------------------------------------------------------------.
@@ -250,6 +253,9 @@ push_string_init (void)
       abort ();
     }

+  /* Prefer reusing an older block, for tail-call optimization.  */
+  while (isp && isp->type == INPUT_STRING && !isp->u.u_s.string[0])
+    pop_input ();
   next = (input_block *) obstack_alloc (current_input,
                                         sizeof (struct input_block));
   next->type = INPUT_STRING;
-- 
2.31.1


_______________________________________________
M4-patches mailing list
M4-patches@gnu.org
https://lists.gnu.org/mailman/listinfo/m4-patches

Reply via email to