Skip to content

Commit 684ce24

Browse files
committed
Improve locale character tables handling and reduce pattern cache size
If a locale other than C is active, character tables are saved into the compile context. Every compiled pattern will have a pointer to the character table, that was present in the context at the time of the pattern compilation. Thus, the cache entries don't need to carry char tables pointer, which reduces their size to 8 bytes on 64-bit. Instead, the generated character tables are tracked in a separate HashTable. If a character table was generated before, it'll be assigned to the compile context when the locale changes. Otherwise a new char table will be generated and cached.
1 parent 34e58a6 commit 684ce24

File tree

1 file changed

+26
-15
lines changed

1 file changed

+26
-15
lines changed

ext/pcre/php_pcre.c

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,6 @@ struct _pcre_cache_entry {
5555
uint32_t compile_options;
5656
uint32_t extra_compile_options;
5757
uint32_t refcount;
58-
#if HAVE_SETLOCALE
59-
const uint8_t *tables;
60-
#endif
6158
};
6259

6360
enum {
@@ -100,6 +97,16 @@ static MUTEX_T pcre_mt = NULL;
10097
#define php_pcre_mutex_unlock()
10198
#endif
10299

100+
#if HAVE_SETLOCALE
101+
ZEND_TLS HashTable char_tables;
102+
103+
static void php_pcre_free_char_table(zval *data)
104+
{/*{{{*/
105+
void *ptr = Z_PTR_P(data);
106+
pefree(ptr, 1);
107+
}/*}}}*/
108+
#endif
109+
103110
static void pcre_handle_exec_error(int pcre_code) /* {{{ */
104111
{
105112
int preg_code = 0;
@@ -141,9 +148,6 @@ static void php_free_pcre_cache(zval *data) /* {{{ */
141148
pcre_cache_entry *pce = (pcre_cache_entry *) Z_PTR_P(data);
142149
if (!pce) return;
143150
pcre2_code_free(pce->re);
144-
#if HAVE_SETLOCALE
145-
if ((void*)pce->tables) pefree((void*)pce->tables, 1);
146-
#endif
147151
pefree(pce, 1);
148152
}
149153
/* }}} */
@@ -262,6 +266,9 @@ static PHP_GINIT_FUNCTION(pcre) /* {{{ */
262266
#endif
263267

264268
php_pcre_init_pcre2(1);
269+
#if HAVE_SETLOCALE
270+
zend_hash_init(&char_tables, 1, NULL, php_pcre_free_char_table, 1);
271+
#endif
265272
}
266273
/* }}} */
267274

@@ -270,6 +277,9 @@ static PHP_GSHUTDOWN_FUNCTION(pcre) /* {{{ */
270277
zend_hash_destroy(&pcre_globals->pcre_cache);
271278

272279
php_pcre_shutdown_pcre2();
280+
#if HAVE_SETLOCALE
281+
zend_hash_destroy(&char_tables);
282+
#endif
273283

274284
php_pcre_mutex_free();
275285
}
@@ -535,6 +545,7 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(zend_string *regex)
535545
size_t pattern_len;
536546
uint32_t poptions = 0;
537547
const uint8_t *tables = NULL;
548+
uint8_t save_tables = 0;
538549
zval *zv;
539550
pcre_cache_entry new_entry;
540551
int rc;
@@ -705,13 +716,11 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(zend_string *regex)
705716

706717
#if HAVE_SETLOCALE
707718
if (key != regex) {
708-
/* XXX a better solution here were to create a copy of cctx
709-
and to cache it along with the generated tables. Once same locale
710-
is encountered, the cached cctx and tables would be fetched.
711-
Currently the tables are generated every time a locale based
712-
pattern is used, and the tables are overwritten in the global
713-
cctx. */
714-
tables = pcre2_maketables(gctx);
719+
tables = (uint8_t *)zend_hash_find_ptr(&char_tables, BG(locale_string));
720+
if (!tables) {
721+
save_tables = 1;
722+
tables = pcre2_maketables(gctx);
723+
}
715724
pcre2_set_character_tables(cctx, tables);
716725
}
717726
#endif
@@ -739,7 +748,7 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(zend_string *regex)
739748
php_error_docref(NULL,E_WARNING, "Compilation failed: %s at offset %zu", error, erroffset);
740749
pcre_handle_exec_error(PCRE2_ERROR_INTERNAL);
741750
efree(pattern);
742-
if (tables) {
751+
if (save_tables) {
743752
pefree((void*)tables, 1);
744753
}
745754
return NULL;
@@ -779,7 +788,9 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(zend_string *regex)
779788
new_entry.compile_options = coptions;
780789
new_entry.extra_compile_options = extra_coptions;
781790
#if HAVE_SETLOCALE
782-
new_entry.tables = tables;
791+
if (save_tables) {
792+
zend_hash_add_ptr(&char_tables, BG(locale_string), (void *)tables);
793+
}
783794
#endif
784795
new_entry.refcount = 0;
785796

0 commit comments

Comments
 (0)