Cache one match context per thread in the PCRE2 shim
ober
2d0a8d8d3f86b9c86114c15e83062acc0aa6e453
--- a/jerboa_pcre2_shim.c +++ b/jerboa_pcre2_shim.c @@ -28,16 +28,31 @@ int jerboa_pcre2_set_match_limits(uint32_t match_limit, uint32_t depth_limit) return 0; } -static pcre2_match_context_8* jerboa_pcre2_make_match_context(void) +/* One cached match context per thread. A PCRE2 match context is reusable + * across matches, so creating and freeing one per call is wasted work; the + * context is (re)configured only when the thread-local limits change. It is + * intentionally retained until thread exit (a single context per thread). */ +static __thread pcre2_match_context_8 *_ffi_match_ctx = NULL; +static __thread uint32_t _ffi_ctx_match_limit = 0; +static __thread uint32_t _ffi_ctx_depth_limit = 0; + +static pcre2_match_context_8* jerboa_pcre2_get_match_context(void) { - pcre2_match_context_8 *ctx = pcre2_match_context_create_8(NULL); - if (!ctx) return NULL; - if (pcre2_set_match_limit_8(ctx, _ffi_match_limit) < 0 || - pcre2_set_depth_limit_8(ctx, _ffi_depth_limit) < 0) { - pcre2_match_context_free_8(ctx); - return NULL; + if (!_ffi_match_ctx) { + _ffi_match_ctx = pcre2_match_context_create_8(NULL); + if (!_ffi_match_ctx) return NULL; + _ffi_ctx_match_limit = 0; + _ffi_ctx_depth_limit = 0; + } + if (_ffi_ctx_match_limit != _ffi_match_limit || + _ffi_ctx_depth_limit != _ffi_depth_limit) { + if (pcre2_set_match_limit_8(_ffi_match_ctx, _ffi_match_limit) < 0 || + pcre2_set_depth_limit_8(_ffi_match_ctx, _ffi_depth_limit) < 0) + return NULL; + _ffi_ctx_match_limit = _ffi_match_limit; + _ffi_ctx_depth_limit = _ffi_depth_limit; } - return ctx; + return _ffi_match_ctx; } pcre2_code_8* jerboa_pcre2_compile( @@ -83,11 +98,10 @@ int jerboa_pcre2_match( if (!code || (!subject && subject_length > 0) || !match_data) return PCRE2_ERROR_NULL; if (startoffset > subject_length) return PCRE2_ERROR_BADOFFSET; - ctx = jerboa_pcre2_make_match_context(); + ctx = jerboa_pcre2_get_match_context(); if (!ctx) return PCRE2_ERROR_NOMEMORY; rc = pcre2_match_8(code, (PCRE2_SPTR8)subject, subject_length, startoffset, options, match_data, ctx); - pcre2_match_context_free_8(ctx); return rc; } @@ -193,7 +207,7 @@ jerboa_pcre2_substitute_result_t* jerboa_pcre2_substitute_create( return result; } - ctx = jerboa_pcre2_make_match_context(); + ctx = jerboa_pcre2_get_match_context(); if (!ctx) { result->code = PCRE2_ERROR_NOMEMORY; return result; @@ -202,7 +216,6 @@ jerboa_pcre2_substitute_result_t* jerboa_pcre2_substitute_create( capacity = subject_length + replacement_length + 256; result->data = (char*)malloc(capacity + 1); if (!result->data) { - pcre2_match_context_free_8(ctx); result->code = PCRE2_ERROR_NOMEMORY; return result; } @@ -240,7 +253,6 @@ jerboa_pcre2_substitute_result_t* jerboa_pcre2_substitute_create( } } - pcre2_match_context_free_8(ctx); result->code = rc; if (rc >= 0) { result->length = outlen; @@ -312,11 +324,10 @@ int jerboa_pcre2_jit_match( if (!code || (!subject && subject_length > 0) || !match_data) return PCRE2_ERROR_NULL; if (startoffset > subject_length) return PCRE2_ERROR_BADOFFSET; - ctx = jerboa_pcre2_make_match_context(); + ctx = jerboa_pcre2_get_match_context(); if (!ctx) return PCRE2_ERROR_NOMEMORY; rc = pcre2_jit_match_8(code, (PCRE2_SPTR8)subject, subject_length, startoffset, options, match_data, ctx); - pcre2_match_context_free_8(ctx); return rc; }