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;