Commit 915318ed9c5 for php.net

commit 915318ed9c51e9f3e95566f9bf9e14f01744b74b
Author: henderkes <m@pyc.ac>
Date:   Thu Jun 11 01:35:26 2026 +0000

    make all static extensions use TSRMG_STATIC

    Closes GH-22277

diff --git a/NEWS b/NEWS
index 9d38664136a..2462f0a73cc 100644
--- a/NEWS
+++ b/NEWS
@@ -33,6 +33,7 @@ PHP                                                                        NEWS
   . Fixed GH-22422 (zend_arena layout mismatch leaked memory in separately
     built extensions under AddressSanitizer). (iliaal)
   . TSRM: use local-exec TLS in PIE executables. (henderkes)
+  . perf: make all static extensions use TSRMG_STATIC. (henderkes)

 - BCMath:
   . Added NUL-byte validation to BCMath functions. (jorgsowa)
diff --git a/UPGRADING b/UPGRADING
index 58bf1f9c9a1..15c1aad15db 100644
--- a/UPGRADING
+++ b/UPGRADING
@@ -490,7 +490,7 @@ PHP 8.6 UPGRADE NOTES
   . The performance of the TAILCALL VM has been improved.
   . The TAILCALL VM is now enabled on Windows when compiling with Clang >= 19
     x86_64.
-  . The performance of ZTS+PIE builds has been improved.
+  . The performance of ZTS builds has been improved.

 - DOM:
   . Made splitText() faster and consume less memory.
diff --git a/build/php.m4 b/build/php.m4
index 83375bec5aa..6d9e3e21387 100644
--- a/build/php.m4
+++ b/build/php.m4
@@ -938,10 +938,14 @@ AC_DEFUN([PHP_NEW_EXTENSION],[

   ifelse($5,,ac_extra=,[ac_extra=$(echo "m4_normalize(m4_expand([$5]))"|$SED s#@ext_srcdir@#$ext_srcdir#g|$SED s#@ext_builddir@#$ext_builddir#g)])

+  dnl Statically linked extensions share the engine's _tsrm_ls_cache symbol,
+  dnl so in ZTS builds they can read the TSRMLS cache directly.
+  ac_extra_static="$ac_extra -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"
+
   if test "$3" != "shared" && test "$3" != "yes" && test "$4" != "cli"; then
 dnl ---------------------------------------------- Static module
     [PHP_]translit($1,a-z_-,A-Z__)[_SHARED]=no
-    PHP_ADD_SOURCES($ext_dir,$2,$ac_extra,)
+    PHP_ADD_SOURCES($ext_dir,$2,$ac_extra_static,)
     EXT_STATIC="$EXT_STATIC $1;$ext_dir"
     if test "$3" != "nocli"; then
       EXT_CLI_STATIC="$EXT_CLI_STATIC $1;$ext_dir"
@@ -962,11 +966,11 @@ dnl ---------------------------------------------- CLI static module
     [PHP_]translit($1,a-z_-,A-Z__)[_SHARED]=no
     case "$PHP_SAPI" in
       cgi|embed|phpdbg[)]
-        PHP_ADD_SOURCES($ext_dir,$2,$ac_extra,)
+        PHP_ADD_SOURCES($ext_dir,$2,$ac_extra_static,)
         EXT_STATIC="$EXT_STATIC $1;$ext_dir"
         ;;
       *[)]
-        PHP_ADD_SOURCES($ext_dir,$2,$ac_extra,cli)
+        PHP_ADD_SOURCES($ext_dir,$2,$ac_extra_static,cli)
         ;;
     esac
     EXT_CLI_STATIC="$EXT_CLI_STATIC $1;$ext_dir"
diff --git a/ext/date/config.w32 b/ext/date/config.w32
index b053e27aae3..150fb1498f3 100644
--- a/ext/date/config.w32
+++ b/ext/date/config.w32
@@ -1,6 +1,6 @@
 // vim:ft=javascript

-EXTENSION("date", "php_date.c", false, "/Iext/date/lib /DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 /DHAVE_TIMELIB_CONFIG_H=1");
+EXTENSION("date", "php_date.c", false, "/Iext/date/lib /DHAVE_TIMELIB_CONFIG_H=1");
 PHP_DATE = "yes";
 ADD_SOURCES("ext/date/lib", "astro.c timelib.c dow.c parse_date.c parse_posix.c parse_tz.c tm2unixtime.c unixtime2tm.c parse_iso_intervals.c interval.c", "date");

diff --git a/ext/date/config0.m4 b/ext/date/config0.m4
index c78fcb78e15..5018f258ab2 100644
--- a/ext/date/config0.m4
+++ b/ext/date/config0.m4
@@ -9,7 +9,7 @@ AX_CHECK_COMPILE_FLAG([-Wno-implicit-fallthrough],

 PHP_DATE_CFLAGS="$PHP_DATE_CFLAGS -DHAVE_TIMELIB_CONFIG_H=1"
 PHP_TIMELIB_CFLAGS="$PHP_DATE_CFLAGS"
-PHP_DATE_CFLAGS="$PHP_DATE_CFLAGS -I@ext_builddir@/lib -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"
+PHP_DATE_CFLAGS="$PHP_DATE_CFLAGS -I@ext_builddir@/lib"

 AX_CHECK_COMPILE_FLAG([-fwrapv],
   [PHP_TIMELIB_CFLAGS="$PHP_TIMELIB_CFLAGS -fwrapv"])
diff --git a/ext/hash/config.m4 b/ext/hash/config.m4
index 2da44c503a6..72b7db8f9de 100644
--- a/ext/hash/config.m4
+++ b/ext/hash/config.m4
@@ -57,7 +57,7 @@ PHP_NEW_EXTENSION([hash], m4_normalize([
     murmur/PMurHash128.c
   ]),
   [no],,
-  [$PHP_HASH_CFLAGS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1])
+  [$PHP_HASH_CFLAGS])
 PHP_ADD_BUILD_DIR([$ext_builddir/murmur])
 AS_VAR_IF([SHA3_DIR],,, [PHP_ADD_BUILD_DIR([$ext_builddir/$SHA3_DIR])])
 PHP_INSTALL_HEADERS([ext/hash], m4_normalize([
diff --git a/ext/hash/config.w32 b/ext/hash/config.w32
index e63efcfd84c..347dbddea6b 100644
--- a/ext/hash/config.w32
+++ b/ext/hash/config.w32
@@ -27,7 +27,7 @@ if (!CHECK_HEADER('KeccakHash.h', 'CFLAGS_HASH', hash_sha3_dir)) {
 	ERROR('Unable to locate SHA3 headers');
 }

-ADD_FLAG('CFLAGS_HASH', '/DKeccakP200_excluded /DKeccakP400_excluded /DKeccakP800_excluded /DZEND_ENABLE_STATIC_TSRMLS_CACHE=1');
+ADD_FLAG('CFLAGS_HASH', '/DKeccakP200_excluded /DKeccakP400_excluded /DKeccakP800_excluded');

 ADD_SOURCES('ext/hash/murmur', 'PMurHash.c PMurHash128.c', 'hash');

diff --git a/ext/json/config.m4 b/ext/json/config.m4
index 5697dbff8d2..a3ae54a7ac2 100644
--- a/ext/json/config.m4
+++ b/ext/json/config.m4
@@ -4,8 +4,7 @@ PHP_NEW_EXTENSION([json], m4_normalize([
     json_scanner.c
     json.c
   ]),
-  [no],,
-  [-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1])
+  [no])
 PHP_INSTALL_HEADERS([ext/json], m4_normalize([
   php_json_parser.h
   php_json_scanner.h
diff --git a/ext/json/config.w32 b/ext/json/config.w32
index 84f77b6f8c9..9d9a37df08a 100644
--- a/ext/json/config.w32
+++ b/ext/json/config.w32
@@ -1,6 +1,6 @@
 // vim:ft=javascript

-EXTENSION('json', 'json.c', false /* never shared */, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
+EXTENSION('json', 'json.c', false /* never shared */);
 PHP_JSON="yes";
 ADD_SOURCES(configure_module_dirname, "json_encoder.c json_parser.tab.c json_scanner.c", "json");

diff --git a/ext/lexbor/config.m4 b/ext/lexbor/config.m4
index a75f490e77c..43123578a72 100644
--- a/ext/lexbor/config.m4
+++ b/ext/lexbor/config.m4
@@ -192,7 +192,7 @@ PHP_NEW_EXTENSION([lexbor], m4_normalize([
     $LEXBOR_DIR/url/url.c
   ]),
   [no],,
-  [-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 $PHP_LEXBOR_CFLAGS])
+  [$PHP_LEXBOR_CFLAGS])

 PHP_ADD_BUILD_DIR([
   $ext_builddir/
diff --git a/ext/lexbor/config.w32 b/ext/lexbor/config.w32
index e75798e0618..403c3b98afb 100644
--- a/ext/lexbor/config.w32
+++ b/ext/lexbor/config.w32
@@ -1,6 +1,6 @@
 // vim:ft=javascript

-EXTENSION("lexbor", "php_lexbor.c", false, "/I " + configure_module_dirname + " /DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
+EXTENSION("lexbor", "php_lexbor.c", false, "/I " + configure_module_dirname);
 PHP_LEXBOR="yes";
 ADD_SOURCES("ext/lexbor/lexbor/ports/windows_nt/lexbor/core", "memory.c", "lexbor");
 ADD_SOURCES("ext/lexbor/lexbor/core", "array_obj.c array.c avl.c bst.c diyfp.c conv.c dobject.c dtoa.c hash.c mem.c mraw.c plog.c print.c serialize.c shs.c str.c strtod.c", "lexbor");
diff --git a/ext/opcache/config.m4 b/ext/opcache/config.m4
index 70138726c56..3798499a451 100644
--- a/ext/opcache/config.m4
+++ b/ext/opcache/config.m4
@@ -339,7 +339,7 @@ PHP_NEW_EXTENSION([opcache], m4_normalize([
     $ZEND_JIT_SRC
   ]),
   [no],,
-  [-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 $JIT_CFLAGS],,
+  [$JIT_CFLAGS],,
   [yes])

 PHP_ADD_EXTENSION_DEP(opcache, date)
diff --git a/ext/opcache/config.w32 b/ext/opcache/config.w32
index 397fa1bdd87..1ad346b4da3 100644
--- a/ext/opcache/config.w32
+++ b/ext/opcache/config.w32
@@ -14,7 +14,7 @@ ZEND_EXTENSION('opcache', "\
 	zend_persist_calc.c \
 	zend_file_cache.c \
 	zend_shared_alloc.c \
-	shared_alloc_win32.c", false, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
+	shared_alloc_win32.c", false);

 ADD_EXTENSION_DEP('opcache', 'date');
 ADD_EXTENSION_DEP('opcache', 'hash');
diff --git a/ext/pcre/config.w32 b/ext/pcre/config.w32
index 7c09456b896..93d9df201d5 100644
--- a/ext/pcre/config.w32
+++ b/ext/pcre/config.w32
@@ -1,7 +1,7 @@
 // vim:ft=javascript

 EXTENSION("pcre", "php_pcre.c", false /* never shared */,
-		"-Iext/pcre/pcre2lib -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
+		"-Iext/pcre/pcre2lib");
 ADD_SOURCES("ext/pcre/pcre2lib", "pcre2_auto_possess.c pcre2_chartables.c pcre2_compile.c pcre2_config.c pcre2_context.c pcre2_chkdint.c pcre2_dfa_match.c pcre2_error.c pcre2_jit_compile.c pcre2_maketables.c pcre2_match.c pcre2_match_data.c pcre2_newline.c pcre2_ord2utf.c pcre2_pattern_info.c pcre2_serialize.c pcre2_string_utils.c pcre2_study.c pcre2_substitute.c  pcre2_substring.c pcre2_tables.c pcre2_ucd.c pcre2_valid_utf.c pcre2_xclass.c pcre2_find_bracket.c pcre2_convert.c pcre2_extuni.c pcre2_script_run.c", "pcre");
 ADD_DEF_FILE("ext\\pcre\\php_pcre.def");

diff --git a/ext/pcre/config0.m4 b/ext/pcre/config0.m4
index e71d9a79557..025b54eb780 100644
--- a/ext/pcre/config0.m4
+++ b/ext/pcre/config0.m4
@@ -57,8 +57,7 @@ if test "$PHP_EXTERNAL_PCRE" != "no"; then

   PHP_NEW_EXTENSION([pcre],
     [php_pcre.c],
-    [no],,
-    [-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1])
+    [no])
   PHP_INSTALL_HEADERS([ext/pcre], [php_pcre.h])
 else
   AC_MSG_CHECKING([for PCRE library to use])
@@ -101,7 +100,6 @@ else
     $PHP_PCRE_CFLAGS
     -DHAVE_CONFIG_H
     -DHAVE_MEMMOVE
-    -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1
     -I@ext_srcdir@/pcre2lib
   "])

diff --git a/ext/random/config.m4 b/ext/random/config.m4
index 484f0549e01..3561d502e70 100644
--- a/ext/random/config.m4
+++ b/ext/random/config.m4
@@ -32,8 +32,7 @@ PHP_NEW_EXTENSION([random], m4_normalize([
     randomizer.c
     zend_utils.c
   ]),
-  [no],,
-  [-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1])
+  [no])
 PHP_INSTALL_HEADERS([ext/random], m4_normalize([
   php_random_csprng.h
   php_random_uint128.h
diff --git a/ext/random/config.w32 b/ext/random/config.w32
index bb0badbd183..fa6788803f0 100644
--- a/ext/random/config.w32
+++ b/ext/random/config.w32
@@ -1,4 +1,4 @@
-EXTENSION("random", "random.c", false /* never shared */, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
+EXTENSION("random", "random.c", false /* never shared */);
 PHP_RANDOM="yes";
 ADD_SOURCES(configure_module_dirname, "csprng.c engine_mt19937.c engine_pcgoneseq128xslrr64.c engine_xoshiro256starstar.c engine_secure.c engine_user.c gammasection.c randomizer.c zend_utils.c", "random");
 PHP_INSTALL_HEADERS("ext/random", "php_random.h php_random_csprng.h php_random_uint128.h random_decl.h");
diff --git a/ext/reflection/config.m4 b/ext/reflection/config.m4
index 10ce256f01a..cd287c14064 100644
--- a/ext/reflection/config.m4
+++ b/ext/reflection/config.m4
@@ -1,4 +1,3 @@
 PHP_NEW_EXTENSION([reflection],
   [php_reflection.c],
-  [no],,
-  [-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1])
+  [no])
diff --git a/ext/reflection/config.w32 b/ext/reflection/config.w32
index 7f000b02ab6..f305095405d 100644
--- a/ext/reflection/config.w32
+++ b/ext/reflection/config.w32
@@ -1,4 +1,4 @@
 // vim:ft=javascript

-EXTENSION("reflection", "php_reflection.c", false /* never shared */, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
+EXTENSION("reflection", "php_reflection.c", false /* never shared */);
 PHP_REFLECTION="yes";
diff --git a/ext/spl/config.m4 b/ext/spl/config.m4
index f15e124ba3f..39e320049c3 100644
--- a/ext/spl/config.m4
+++ b/ext/spl/config.m4
@@ -10,8 +10,7 @@ PHP_NEW_EXTENSION([spl], m4_normalize([
     spl_iterators.c
     spl_observer.c
   ]),
-  [no],,
-  [-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1])
+  [no])
 PHP_INSTALL_HEADERS([ext/spl], m4_normalize([
   php_spl.h
   spl_array.h
diff --git a/ext/spl/config.w32 b/ext/spl/config.w32
index 06e87c66335..4044e05ecb4 100644
--- a/ext/spl/config.w32
+++ b/ext/spl/config.w32
@@ -1,5 +1,5 @@
 // vim:ft=javascript

-EXTENSION("spl", "php_spl.c spl_functions.c spl_iterators.c spl_array.c spl_directory.c spl_exceptions.c spl_observer.c spl_dllist.c spl_heap.c spl_fixedarray.c", false /*never shared */, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
+EXTENSION("spl", "php_spl.c spl_functions.c spl_iterators.c spl_array.c spl_directory.c spl_exceptions.c spl_observer.c spl_dllist.c spl_heap.c spl_fixedarray.c", false /*never shared */);
 PHP_SPL="yes";
 PHP_INSTALL_HEADERS("ext/spl", "php_spl.h spl_array.h spl_directory.h spl_exceptions.h spl_functions.h spl_iterators.h spl_observer.h spl_dllist.h spl_heap.h spl_fixedarray.h");
diff --git a/ext/standard/config.m4 b/ext/standard/config.m4
index 67c36b93ba3..7edfcf1da1f 100644
--- a/ext/standard/config.m4
+++ b/ext/standard/config.m4
@@ -453,8 +453,7 @@ PHP_NEW_EXTENSION([standard], m4_normalize([
     versioning.c
     $php_ext_standard_sources
   ]),
-  [no],,
-  [-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1])
+  [no])

 PHP_ADD_BUILD_DIR([$ext_builddir/libavifinfo])

diff --git a/ext/standard/config.w32 b/ext/standard/config.w32
index 50031ac3b8a..56096097620 100644
--- a/ext/standard/config.w32
+++ b/ext/standard/config.w32
@@ -36,8 +36,7 @@ EXTENSION("standard", "array.c base64.c basic_functions.c browscap.c \
 	php_fopen_wrapper.c credits.c css.c var_unserializer.c ftok.c sha1.c \
 	user_filters.c uuencode.c filters.c proc_open.c password.c \
 	streamsfuncs.c http.c flock_compat.c hrtime.c",
-	false /* never shared */,
-	'/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1');
+	false /* never shared */);
 ADD_SOURCES("ext/standard/libavifinfo", "avifinfo.c", "standard");
 PHP_STANDARD = "yes";
 ADD_MAKEFILE_FRAGMENT();
diff --git a/ext/uri/config.m4 b/ext/uri/config.m4
index 31d6c0e10c8..a518cf84b3b 100644
--- a/ext/uri/config.m4
+++ b/ext/uri/config.m4
@@ -39,7 +39,7 @@ else
   PHP_EVAL_INCLINE([$LIBURIPARSER_CFLAGS])
 fi

-PHP_NEW_EXTENSION(uri, [php_uri.c php_uri_common.c uri_parser_rfc3986.c uri_parser_whatwg.c uri_parser_php_parse_url.c $URIPARSER_SOURCES], [no],,[$URI_CFLAGS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1])
+PHP_NEW_EXTENSION(uri, [php_uri.c php_uri_common.c uri_parser_rfc3986.c uri_parser_whatwg.c uri_parser_php_parse_url.c $URIPARSER_SOURCES], [no],,[$URI_CFLAGS])
 PHP_ADD_EXTENSION_DEP(uri, lexbor)

 if test "$PHP_EXTERNAL_URIPARSER" = "no"; then
diff --git a/ext/uri/config.w32 b/ext/uri/config.w32
index 2bed937a737..597ffb9fa03 100644
--- a/ext/uri/config.w32
+++ b/ext/uri/config.w32
@@ -1,4 +1,4 @@
-EXTENSION("uri", "php_uri.c php_uri_common.c uri_parser_rfc3986.c uri_parser_whatwg.c uri_parser_php_parse_url.c", false /* never shared */, "/I ext/lexbor /I ext/uri/uriparser/include /DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
+EXTENSION("uri", "php_uri.c php_uri_common.c uri_parser_rfc3986.c uri_parser_whatwg.c uri_parser_php_parse_url.c", false /* never shared */, "/I ext/lexbor /I ext/uri/uriparser/include");

 AC_DEFINE("URI_ENABLE_ANSI", 1, "Define to 1 for enabling ANSI support of uriparser.")
 AC_DEFINE("URI_NO_UNICODE", 1, "Define to 1 for disabling unicode support of uriparser.")
diff --git a/win32/build/confutils.js b/win32/build/confutils.js
index b7289bbcb27..3751101daa4 100644
--- a/win32/build/confutils.js
+++ b/win32/build/confutils.js
@@ -1494,6 +1494,9 @@ function EXTENSION(extname, file_list, shared, cflags, dllname, obj_dir)
 		ADD_FLAG("CFLAGS_PHP", "/D COMPILE_DL_" + EXT);
 	} else {
 		STDOUT.WriteLine("Enabling extension " + extname_for_printing);
+		/* Statically linked extensions share the engine's _tsrm_ls_cache symbol,
+		 * so in ZTS builds they can read the TSRMLS cache directly. */
+		cflags = "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 " + cflags;
 	}

 	MFO.WriteBlankLines(1);