Skip to content

Commit 1a871ce

Browse files
committed
AHOCORASICK - Reduce heap allocation overhead
A `U8*` structure is used to track character positions during Aho-Corasick string searching. This used to always be allocated from the heap, and wrapped in a mortal SV to avoid leakage. However, that incurs overhead. Following this commit: * A stack buffer is used if `maxlen` is small enough. * Otherwise, the heap allocation is saved directly to the savestack for freeing during stack unwinding. * Since a mortal SV is no longer used, there is no need to `SAVETMPS` and `FREETMPS` at scope entry/exit.
1 parent a2ff23c commit 1a871ce

File tree

1 file changed

+30
-17
lines changed

1 file changed

+30
-17
lines changed

regexec.c

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3258,29 +3258,40 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s,
32583258
const char *real_start = s;
32593259
#endif
32603260
STRLEN maxlen = trie->maxlen;
3261-
SV *sv_points;
32623261
U8 **points; /* map of where we were in the input string
32633262
when reading a given char. For ASCII this
32643263
is unnecessary overhead as the relationship
32653264
is always 1:1, but for Unicode, especially
32663265
case folded Unicode this is not true. */
3266+
3267+
/* For a shorter maxlen, points are stored in a stack buffer. */
3268+
/* The choice of STACK_POINTS_MAX here is rather arbitrary.
3269+
* When building perl and running test_harness, maxlen rarely
3270+
* goes above 8, but presumbaly there are good business cases
3271+
* where a somewhat larger value is common. */
3272+
enum { STACK_POINTS_MAX = 32 };
3273+
U8 *points_stack[STACK_POINTS_MAX];
3274+
/* Otherwise, a more costly heap allocation is used. */
3275+
bool used_heap = false;
3276+
32673277
U8 foldbuf[ UTF8_MAXBYTES_CASE + 1 ];
32683278
U8 *bitmap = NULL;
3269-
3279+
U8 **points_heap = NULL;
32703280

32713281
DECLARE_AND_GET_RE_DEBUG_FLAGS;
32723282

3273-
/* We can't just allocate points here. We need to wrap it in
3274-
* an SV so it gets freed properly if there is a croak while
3275-
* running the match */
3276-
ENTER;
3277-
SAVETMPS;
3278-
sv_points = newSV(maxlen * sizeof(U8 *));
3279-
SvCUR_set(sv_points,
3280-
maxlen * sizeof(U8 *));
3281-
SvPOK_on(sv_points);
3282-
sv_2mortal(sv_points);
3283-
points = (U8**)SvPV_nolen(sv_points );
3283+
if (maxlen <= STACK_POINTS_MAX) {
3284+
points = points_stack;
3285+
} else {
3286+
used_heap = true;
3287+
/* In case of a die event, the allocation will be freed
3288+
as the savestack is unwound. */
3289+
ENTER;
3290+
Newx(points_heap, maxlen, U8*);
3291+
SAVEFREEPV(points_heap);
3292+
points = points_heap;
3293+
}
3294+
32843295
if ( trie_type != trie_utf8_fold
32853296
&& (trie->bitmap || OP(c)==AHOCORASICKC) )
32863297
{
@@ -3464,8 +3475,9 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s,
34643475
);
34653476
});
34663477
if (reginfo->intuit || regtry(reginfo, &s)) {
3467-
FREETMPS;
3468-
LEAVE;
3478+
if (used_heap) {
3479+
LEAVE;
3480+
}
34693481
goto got_it;
34703482
}
34713483
if (s < reginfo->strend) {
@@ -3482,8 +3494,9 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s,
34823494
break;
34833495
}
34843496
}
3485-
FREETMPS;
3486-
LEAVE;
3497+
if (used_heap) {
3498+
LEAVE;
3499+
}
34873500
}
34883501
break;
34893502

0 commit comments

Comments
 (0)