Commit 834b129f4b for perl

commit 834b129f4b61392076c1d1c6e20180717ff5f8f3
Author: Richard Leach <rich+perl@hyphen-dash-hyphen.info>
Date:   Sat Oct 24 22:09:15 2026 +0000

    regexec.c: S_cleanup_regmatch_info_aux now clears offs_spare_used

    https://github.com/Perl/perl5/pull/24412 enabled reuse of the first
    `regexp_paren_pair‎` chunk to be allocated by an executed regular
    expression. A boolean flag (`offs_spare_used`) shows whether or not
    that chunk is currently in use. The flag is cleared by a destructor
    pushed onto the savestack.

    A dedicated destructor (`S_clear_offs_spare`) was added originally,
    intended to simplify debugging on the off-chance that bugs were
    revealed via CPAN testing. No bugs have shown up.

    The only task of `S_clear_offs_spare` is to toggle the boolean flag,
    making the overhead-to-actual-work ratio extremely poor. This commit
    removes this dedicated destructor and folds its single task into the
    pre-existing `S_cleanup_regmatch_info_aux` destructor.

diff --git a/embed.fnc b/embed.fnc
index 81d66bfbe7..7302951bfa 100644
--- a/embed.fnc
+++ b/embed.fnc
@@ -6120,8 +6120,6 @@ EWi	|void	|capture_clear	|NN regexp *rex 			\
 				|U16 from_ix				\
 				|U16 to_ix				\
 				|NN const char *str
-ES	|void	|clear_offs_spare					\
-				|NN void *arg
 ERS	|char * |find_byclass	|NN regexp *prog			\
 				|NN const regnode *c			\
 				|SPTR char *s				\
diff --git a/embed.h b/embed.h
index db86800cc5..ab0e816080 100644
--- a/embed.h
+++ b/embed.h
@@ -2184,7 +2184,6 @@
 #     define backup_one_SB(a,b,c)               S_backup_one_SB(aTHX_ a,b,c)
 #     define backup_one_WB_but_over_Extend_FO(a,b,c,d) S_backup_one_WB_but_over_Extend_FO(aTHX_ a,b,c,d)
 #     define capture_clear(a,b,c,d)             S_capture_clear(aTHX_ a,b,c,d comma_aDEPTH)
-#     define clear_offs_spare(a)                S_clear_offs_spare(aTHX_ a)
 #     define find_byclass(a,b,c,d,e)            S_find_byclass(aTHX_ a,b,c,d,e)
 #     define find_next_masked                   S_find_next_masked
 #     define find_span_end                      S_find_span_end
diff --git a/proto.h b/proto.h
index 9c099efb17..19ecdc28d8 100644
--- a/proto.h
+++ b/proto.h
@@ -15958,11 +15958,6 @@ S_unwind_scan_frames(pTHX_ void *p)
                   PERL_UNUSED_CONTEXT_FOR_ARGS_ASSERT;                         \
     } STMT_END

-# define PERL_ARGS_ASSERT_CLEAR_OFFS_SPARE      \
-     STMT_START { Perl_assert_aTHX; assert(arg);        \
-                  PERL_UNUSED_CONTEXT_FOR_ARGS_ASSERT;  \
-    } STMT_END
-
 # define PERL_ARGS_ASSERT_FIND_BYCLASS          \
      STMT_START { Perl_assert_aTHX; assert(prog); assert(c); assert(s);  \
                   assert(strend); assert(s <= strend);                   \
@@ -16133,10 +16128,6 @@ S_backup_one_WB_but_over_Extend_FO(pTHX_ WB_enum *previous, const U8 * const str
         Perl_attribute_nonnull(pTHX_2)
         Perl_attribute_nonnull(pTHX_3)
         __attribute__warn_unused_result__;
-static void
-S_clear_offs_spare(pTHX_ void *arg)
-        Perl_attribute_nonnull_aTHX
-        Perl_attribute_nonnull(pTHX_1);
 static char *
 S_find_byclass(pTHX_ regexp *prog, const regnode *c, char *s, const char *strend, regmatch_info *reginfo)
         Perl_attribute_nonnull_aTHX
diff --git a/regexec.c b/regexec.c
index 8478caa030..3196e05cb5 100644
--- a/regexec.c
+++ b/regexec.c
@@ -3777,18 +3777,6 @@ S_reg_set_capture_string(pTHX_ REGEXP * const rx,
     }
 }

-
-
-
-static void
-S_clear_offs_spare(pTHX_ void *arg)
-{
-    PERL_ARGS_ASSERT_CLEAR_OFFS_SPARE;
-
-    regexp *prog = (regexp *)arg;
-    prog->offs_spare_used = FALSE;
-}
-
 /*
  - regexec_flags - match a regexp against a string
  */
@@ -4033,6 +4021,7 @@ Perl_regexec_flags(pTHX_ REGEXP * const rx, char *stringarg, char *strend,
         reginfo->info_aux->old_regmatch_state = old_regmatch_state;
         reginfo->info_aux->old_regmatch_slab  = old_regmatch_slab;
         reginfo->info_aux->rexi = progi;
+        reginfo->info_aux->offs_spare_prog = NULL;

         SAVEDESTRUCTOR_X(S_cleanup_regmatch_info_aux, reginfo->info_aux);

@@ -4090,9 +4079,12 @@ Perl_regexec_flags(pTHX_ REGEXP * const rx, char *stringarg, char *strend,
              * does not do a calloc+free in every loop iteration.*/
             regexp_paren_pair * const old_offs_spare = prog->offs_spare;
             prog->offs_spare = swap; /* Stash the successful match offs */
+
+            /* S_cleanup_regmatch_info_aux() later clears this */
+            reginfo->info_aux->offs_spare_prog = prog;
+
             prog->offs_spare_used = TRUE;
             offs_spare_used = TRUE;
-            SAVEDESTRUCTOR_X(S_clear_offs_spare, prog);

             if (old_offs_spare) {
                 /* Nice! There is already a buffer ready to use. */
@@ -11821,6 +11813,10 @@ S_cleanup_regmatch_info_aux(pTHX_ void *arg)
     assert(rexi->depth > 0);
     rexi->depth--;

+    /* the offs_spare allocation is available for reuse */
+    if (aux->offs_spare_prog)
+        aux->offs_spare_prog->offs_spare_used = FALSE;
+
     /* free any allocated super-linear caches */
     if (aux->slc) {
         U8 i;
diff --git a/regexp.h b/regexp.h
index e9aaac1c8e..dab3be3e1d 100644
--- a/regexp.h
+++ b/regexp.h
@@ -815,6 +815,7 @@ typedef struct {
     struct regmatch_state *old_regmatch_state; /* saved PL_regmatch_state */
     struct regmatch_slab  *old_regmatch_slab;  /* saved PL_regmatch_slab */
     struct slc_cache_item *slc; /* current super-liner cache array */
+    struct regexp *offs_spare_prog; /* prog is using the offs_spare */
 } regmatch_info_aux;