Commit da59f3a8d17 for php
commit da59f3a8d179db1b56e899fbec9ace1de97720e7
Author: Marc <m@pyc.ac>
Date: Mon Nov 2 22:23:45 2026 +0700
perf: move EG() and CG() in ZTS builds into __thread storage (#23227)
diff --git a/.gdbinit b/.gdbinit
index 4477828265e..df4cbffb5fa 100644
--- a/.gdbinit
+++ b/.gdbinit
@@ -3,18 +3,22 @@ define set_ts
end
document set_ts
- set the ts resource, it is impossible for gdb to
- call ts_resource_ex while no process is running,
- but we could get the resource from the argument
- of frame info.
+ set a legacy TSRM resource cache pointer when it is available
+ from a frame argument. Pass 0 to use the current thread's
+ direct executor and compiler globals.
end
define ____executor_globals
if basic_functions_module.zts
- set $tsrm_ls = _tsrm_ls_cache
- set $eg = ((zend_executor_globals*) (*((void ***) $tsrm_ls))[executor_globals_id-1])
- set $cg = ((zend_compiler_globals*) (*((void ***) $tsrm_ls))[compiler_globals_id-1])
- set $eg_ptr = $eg
+ if !$tsrm_ls
+ set $eg = _tsrm_ls_cache.eg
+ set $cg = _tsrm_ls_cache.cg
+ set $eg_ptr = (zend_executor_globals*) &_tsrm_ls_cache.eg
+ else
+ set $eg = ((zend_executor_globals*) (*((void ***) $tsrm_ls))[executor_globals_id-1])
+ set $cg = ((zend_compiler_globals*) (*((void ***) $tsrm_ls))[compiler_globals_id-1])
+ set $eg_ptr = $eg
+ end
else
set $eg = executor_globals
set $cg = compiler_globals
diff --git a/TSRM/TSRM.c b/TSRM/TSRM.c
index 089520041e3..0cc19247311 100644
--- a/TSRM/TSRM.c
+++ b/TSRM/TSRM.c
@@ -59,7 +59,6 @@ static int resource_types_table_size;
/* Reserved space for fast globals access */
static size_t tsrm_reserved_pos = 0;
static size_t tsrm_reserved_size = 0;
-static size_t tsrm_reserved_front = 0;
static MUTEX_T tsmm_mutex; /* thread-safe memory manager mutex */
static MUTEX_T tsrm_env_mutex; /* tsrm environ mutex */
@@ -168,7 +167,6 @@ TSRM_API bool tsrm_startup(int expected_threads, int expected_resources, int deb
tsrm_reserved_pos = 0;
tsrm_reserved_size = 0;
- tsrm_reserved_front = 0;
tsrm_env_mutex = tsrm_mutex_alloc();
tsrm_atexit_init();
@@ -229,7 +227,7 @@ TSRM_API void tsrm_shutdown(void)
} else {
free(p->storage);
}
- free((char *) p - tsrm_reserved_front);
+ free(p);
p = next_p;
}
}
@@ -261,7 +259,6 @@ TSRM_API void tsrm_shutdown(void)
tsrm_reserved_pos = 0;
tsrm_reserved_size = 0;
- tsrm_reserved_front = 0;
}/*}}}*/
/* {{{ */
@@ -354,19 +351,10 @@ TSRM_API void tsrm_reserve(size_t size)
}/*}}}*/
-/* Carve a fixed-offset front region out of the reserved space. It is placed
- * before the TLS entry, so the hot globals get compile-time-constant negative
- * offsets from the cache pointer. */
-TSRM_API void tsrm_reserve_fast_front(size_t size)
-{
- tsrm_reserved_front = TSRM_ALIGNED_SIZE(size);
- tsrm_reserved_size -= tsrm_reserved_front;
-}
-
-
/* allocates a new fast thread-safe-resource id */
TSRM_API ts_rsrc_id ts_allocate_fast_id(ts_rsrc_id *rsrc_id, size_t *offset, size_t size, ts_allocate_ctor ctor, ts_allocate_dtor dtor)
{/*{{{*/
+ TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Obtaining a new fast resource id, %d bytes", size));
tsrm_mutex_lock(tsmm_mutex);
size = TSRM_ALIGNED_SIZE(size);
if (tsrm_reserved_size - tsrm_reserved_pos < size) {
@@ -376,27 +364,13 @@ TSRM_API ts_rsrc_id ts_allocate_fast_id(ts_rsrc_id *rsrc_id, size_t *offset, siz
tsrm_mutex_unlock(tsmm_mutex);
return 0;
}
- ptrdiff_t fixed_offset = TSRM_ALIGNED_SIZE(sizeof(tsrm_tls_entry)) + tsrm_reserved_pos;
+ *offset = TSRM_ALIGNED_SIZE(sizeof(tsrm_tls_entry)) + tsrm_reserved_pos;
tsrm_reserved_pos += size;
- tsrm_mutex_unlock(tsmm_mutex);
-
- return ts_allocate_fast_id_at(rsrc_id, offset, fixed_offset, size, ctor, dtor);
-}/*}}}*/
-
-
-TSRM_API ts_rsrc_id ts_allocate_fast_id_at(ts_rsrc_id *rsrc_id, size_t *offset, ptrdiff_t fixed_offset, size_t size, ts_allocate_ctor ctor, ts_allocate_dtor dtor)
-{
- TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Obtaining a new fast resource id, %d bytes", size));
-
- tsrm_mutex_lock(tsmm_mutex);
/* obtain a resource id */
*rsrc_id = TSRM_SHUFFLE_RSRC_ID(id_count++);
TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Obtained resource id %d", *rsrc_id));
- size = TSRM_ALIGNED_SIZE(size);
- *offset = (size_t) fixed_offset;
-
/* store the new resource type in the resource sizes table */
if (resource_types_table_size < id_count) {
tsrm_resource_type *_tmp;
@@ -423,7 +397,7 @@ TSRM_API ts_rsrc_id ts_allocate_fast_id_at(ts_rsrc_id *rsrc_id, size_t *offset,
TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Successfully allocated new resource id %d", *rsrc_id));
return *rsrc_id;
-}
+}/*}}}*/
/* allocates a resource id whose per-thread storage is a native __thread block */
TSRM_API ts_rsrc_id ts_allocate_tls_id(ts_rsrc_id *rsrc_id, void *(*tls_addr)(void), size_t size, ts_allocate_ctor ctor, ts_allocate_dtor dtor)
@@ -471,10 +445,8 @@ static void set_thread_local_storage_resource_to(tsrm_tls_entry *thread_resource
static void allocate_new_resource(tsrm_tls_entry **thread_resources_ptr, THREAD_T thread_id)
{/*{{{*/
TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Creating data structures for thread %x", thread_id));
- /* The entry follows the fixed-offset front region.
- * hot globals live at negative offsets from the TLS cache pointer. */
- char *block = (char *) malloc(tsrm_reserved_front + TSRM_ALIGNED_SIZE(sizeof(tsrm_tls_entry)) + tsrm_reserved_size);
- (*thread_resources_ptr) = (tsrm_tls_entry *) (block + tsrm_reserved_front);
+ /* Fast resources live in the reserved space right behind the entry. */
+ (*thread_resources_ptr) = (tsrm_tls_entry *) malloc(TSRM_ALIGNED_SIZE(sizeof(tsrm_tls_entry)) + tsrm_reserved_size);
(*thread_resources_ptr)->storage = NULL;
if (id_count > 0) {
(*thread_resources_ptr)->storage = (void **) malloc(sizeof(void *)*id_count);
@@ -587,7 +559,7 @@ TSRM_API void *ts_resource_ex(ts_rsrc_id id, THREAD_T *th_id)
/* The dead thread's native TLS is gone, and its remaining resource dtors
* may depend on those globals. Only release directly owned allocations. */
ts_free_resources(thread_resources, false, false);
- free((char *) thread_resources - tsrm_reserved_front);
+ free(thread_resources);
/* Allocate a new resource at the same point in the linked list, and relink the next pointer */
allocate_new_resource(last_thread_resources, thread_id);
thread_resources = *last_thread_resources;
@@ -640,7 +612,7 @@ void ts_free_thread(void)
tsrm_atexit_set_data(NULL);
TSRMLS_CACHE = NULL;
if (thread_resources) {
- free((char *) thread_resources - tsrm_reserved_front);
+ free(thread_resources);
}
tsrm_mutex_unlock(tsmm_mutex);
}/*}}}*/
diff --git a/TSRM/TSRM.h b/TSRM/TSRM.h
index 90e4b072077..1c66c74a5d0 100644
--- a/TSRM/TSRM.h
+++ b/TSRM/TSRM.h
@@ -95,11 +95,6 @@ TSRM_API ts_rsrc_id ts_allocate_id(ts_rsrc_id *rsrc_id, size_t size, ts_allocate
TSRM_API void tsrm_reserve(size_t size);
TSRM_API ts_rsrc_id ts_allocate_fast_id(ts_rsrc_id *rsrc_id, size_t *offset, size_t size, ts_allocate_ctor ctor, ts_allocate_dtor dtor);
-/* Fast resources at caller-chosen, compile-time-constant offsets. The fixed
- * front region must be reserved after tsrm_reserve() and before any fast id. */
-TSRM_API void tsrm_reserve_fast_front(size_t size);
-TSRM_API ts_rsrc_id ts_allocate_fast_id_at(ts_rsrc_id *rsrc_id, size_t *offset, ptrdiff_t fixed_offset, size_t size, ts_allocate_ctor ctor, ts_allocate_dtor dtor);
-
/* Resource whose per-thread storage is a native __thread block.
* Must be called at startup before any other thread exists. */
TSRM_API ts_rsrc_id ts_allocate_tls_id(ts_rsrc_id *rsrc_id, void *(*tls_addr)(void), size_t size, ts_allocate_ctor ctor, ts_allocate_dtor dtor);
@@ -168,7 +163,7 @@ TSRM_API bool tsrm_is_managed_thread(void);
|| defined(__MUSL__) || defined(__HAIKU__) || defined(_AIX)
# define TSRM_TLS_MODEL_ATTR
# define TSRM_TLS_MODEL_DEFAULT
-#elif defined(__PIC__) && !defined(__PIE__)
+#elif (defined(__PIC__) && !defined(__PIE__)) || !defined(ZEND_ENABLE_STATIC_TSRMLS_CACHE)
# if defined(TSRM_TLS_MODEL_USE_DEFAULT)
# define TSRM_TLS_MODEL_ATTR
# define TSRM_TLS_MODEL_DEFAULT
@@ -193,17 +188,41 @@ TSRM_API bool tsrm_is_managed_thread(void);
#define TSRMG_BULK_STATIC(id, type) ((type) (*((void ***) TSRMLS_CACHE))[TSRM_UNSHUFFLE_RSRC_ID(id)])
#define TSRMG_FAST_STATIC(offset, type, element) (TSRMG_FAST_BULK_STATIC(offset, type)->element)
#define TSRMG_FAST_BULK_STATIC(offset, type) ((type) (((char*) TSRMLS_CACHE)+(offset)))
+
+/* Windows can't dllexport __declspec(thread) symbols, so outside Zend each module
+ * keeps a per-module `void *` pointer and reaches EG/CG via the resource-id indirection. */
+#ifdef ZEND_WIN32
+# define ZEND_TLS_API
+# ifdef LIBZEND_EXPORTS
+# define ZEND_TLS_DIRECT 1
+# endif
+#else
+# define ZEND_TLS_API ZEND_API
+# define ZEND_TLS_DIRECT 1
+#endif
+
+typedef struct _zend_tsrm_ls_cache zend_tsrm_ls_cache;
+
+#ifdef ZEND_TLS_DIRECT
+# define ZEND_TSRMLS_CACHE_T zend_tsrm_ls_cache
+# define TSRMLS_CACHE_DEFINE()
+extern ZEND_TLS_API TSRM_TLS TSRM_TLS_MODEL_ATTR zend_tsrm_ls_cache _tsrm_ls_cache;
+# define ZEND_TSRM_CACHE_PTR (&_tsrm_ls_cache)
+# define ZEND_TSRMG_DIRECT(id, type, member, element) (ZEND_TSRM_CACHE_PTR->member.element)
+#else
+# define ZEND_TSRMLS_CACHE_T void *
+# define TSRMLS_CACHE_DEFINE() TSRM_TLS void *_tsrm_ls_cache = NULL;
+# define ZEND_TSRMG_DIRECT(id, type, member, element) ZEND_TSRMG(id, type, element)
+#endif
#ifdef __cplusplus
-#define TSRMLS_MAIN_CACHE_EXTERN() extern "C" { extern TSRM_TLS void *TSRMLS_CACHE TSRM_TLS_MODEL_ATTR; }
-#define TSRMLS_CACHE_EXTERN() extern "C" { extern TSRM_TLS void *TSRMLS_CACHE; }
+#define TSRMLS_MAIN_CACHE_EXTERN() extern "C" { extern TSRM_TLS ZEND_TSRMLS_CACHE_T _tsrm_ls_cache TSRM_TLS_MODEL_ATTR; }
+#define TSRMLS_CACHE_EXTERN() extern "C" { extern TSRM_TLS ZEND_TSRMLS_CACHE_T _tsrm_ls_cache; }
#else
-#define TSRMLS_MAIN_CACHE_EXTERN() extern TSRM_TLS void *TSRMLS_CACHE TSRM_TLS_MODEL_ATTR;
-#define TSRMLS_CACHE_EXTERN() extern TSRM_TLS void *TSRMLS_CACHE;
+#define TSRMLS_MAIN_CACHE_EXTERN() extern TSRM_TLS ZEND_TSRMLS_CACHE_T _tsrm_ls_cache TSRM_TLS_MODEL_ATTR;
+#define TSRMLS_CACHE_EXTERN() extern TSRM_TLS ZEND_TSRMLS_CACHE_T _tsrm_ls_cache;
#endif
-#define TSRMLS_MAIN_CACHE_DEFINE() TSRM_TLS void *TSRMLS_CACHE TSRM_TLS_MODEL_ATTR = NULL;
-#define TSRMLS_CACHE_DEFINE() TSRM_TLS void *TSRMLS_CACHE = NULL;
#define TSRMLS_CACHE_UPDATE() TSRMLS_CACHE = tsrm_get_ls_cache()
-#define TSRMLS_CACHE _tsrm_ls_cache
+#define TSRMLS_CACHE (*(void **) &_tsrm_ls_cache)
#ifdef __cplusplus
}
@@ -216,7 +235,6 @@ TSRM_API bool tsrm_is_managed_thread(void);
#define TSRMG_STATIC(id, type, element)
#define TSRMLS_MAIN_CACHE_EXTERN()
-#define TSRMLS_MAIN_CACHE_DEFINE()
#define TSRMLS_CACHE_EXTERN()
#define TSRMLS_CACHE_DEFINE()
#define TSRMLS_CACHE_UPDATE()
diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS
index b8ed6552d4f..9eae8540351 100644
--- a/UPGRADING.INTERNALS
+++ b/UPGRADING.INTERNALS
@@ -51,6 +51,8 @@ PHP 8.7 INTERNALS UPGRADE NOTES
allowed anymore. User-facing HashTables must have pDestructor = ZVAL_PTR_DTOR
or NULL, and must be freed with zend_array_destroy(). Other HashTables can be
freed with zend_hash_destroy() + pefree().
+- The ZTS symbols compiler_globals_offset and executor_globals_offset have been
+ removed: CG()/EG() now reach the globals through a __thread struct.
========================
2. Build system changes
diff --git a/Zend/zend.c b/Zend/zend.c
index 46693d92d6f..d921c9f74b6 100644
--- a/Zend/zend.c
+++ b/Zend/zend.c
@@ -52,16 +52,16 @@ static bool startup_done = false;
#ifdef ZTS
ZEND_API int compiler_globals_id;
ZEND_API int executor_globals_id;
-ZEND_API size_t compiler_globals_offset;
-ZEND_API size_t executor_globals_offset;
+ZEND_TLS_API TSRM_TLS TSRM_TLS_MODEL_ATTR zend_tsrm_ls_cache _tsrm_ls_cache = {0};
/* ts_allocate_tls_id takes a callback so each thread resolves its own block.
* A plain &language_scanner_globals would capture only the registering thread's address. */
+static void *executor_globals_tls_addr(void) { return &_tsrm_ls_cache.eg; }
+static void *compiler_globals_tls_addr(void) { return &_tsrm_ls_cache.cg; }
static void *language_scanner_globals_tls_addr(void) { return &language_scanner_globals; }
static HashTable *global_function_table = NULL;
static HashTable *global_class_table = NULL;
static HashTable *global_constants_table = NULL;
static HashTable *global_auto_globals_table = NULL;
-TSRMLS_MAIN_CACHE_DEFINE()
# define GLOBAL_FUNCTION_TABLE global_function_table
# define GLOBAL_CLASS_TABLE global_class_table
# define GLOBAL_CONSTANTS_TABLE global_constants_table
@@ -1031,11 +1031,9 @@ void zend_startup(zend_utility_functions *utility_functions) /* {{{ */
zend_init_rsrc_list_dtors();
#ifdef ZTS
- ts_allocate_fast_id_at(&compiler_globals_id, &compiler_globals_offset, ZEND_CG_OFFSET, sizeof(zend_compiler_globals), (ts_allocate_ctor) compiler_globals_ctor, (ts_allocate_dtor) compiler_globals_dtor);
- ts_allocate_fast_id_at(&executor_globals_id, &executor_globals_offset, ZEND_EG_OFFSET, sizeof(zend_executor_globals), (ts_allocate_ctor) executor_globals_ctor, (ts_allocate_dtor) executor_globals_dtor);
+ ts_allocate_tls_id(&compiler_globals_id, compiler_globals_tls_addr, sizeof(zend_compiler_globals), (ts_allocate_ctor) compiler_globals_ctor, (ts_allocate_dtor) compiler_globals_dtor);
+ ts_allocate_tls_id(&executor_globals_id, executor_globals_tls_addr, sizeof(zend_executor_globals), (ts_allocate_ctor) executor_globals_ctor, (ts_allocate_dtor) executor_globals_dtor);
ts_allocate_tls_id(&language_scanner_globals_id, language_scanner_globals_tls_addr, sizeof(zend_php_scanner_globals), (ts_allocate_ctor) php_scanner_globals_ctor, NULL);
- ZEND_ASSERT(compiler_globals_offset == ZEND_CG_OFFSET);
- ZEND_ASSERT(executor_globals_offset == ZEND_EG_OFFSET);
ts_allocate_fast_id(&ini_scanner_globals_id, &ini_scanner_globals_offset, sizeof(zend_ini_scanner_globals), (ts_allocate_ctor) ini_scanner_globals_ctor, NULL);
compiler_globals = ts_resource(compiler_globals_id);
executor_globals = ts_resource(executor_globals_id);
diff --git a/Zend/zend_gc.c b/Zend/zend_gc.c
index cd7c3c512da..f57e69de740 100644
--- a/Zend/zend_gc.c
+++ b/Zend/zend_gc.c
@@ -306,12 +306,12 @@ typedef struct _zend_gc_globals {
#ifdef ZTS
static int gc_globals_id;
-static size_t gc_globals_offset;
-#define GC_G(v) ZEND_TSRMG_FAST(gc_globals_offset, zend_gc_globals *, v)
+static TSRM_TLS TSRM_TLS_MODEL_ATTR zend_gc_globals gc_globals;
+static void *gc_globals_tls_addr(void) { return &gc_globals; }
#else
-#define GC_G(v) (gc_globals.v)
static zend_gc_globals gc_globals;
#endif
+#define GC_G(v) (gc_globals.v)
#if GC_BENCH
# define GC_BENCH_INC(counter) GC_G(counter)++
@@ -549,7 +549,7 @@ static void gc_globals_ctor_ex(zend_gc_globals *gc_globals)
void gc_globals_ctor(void)
{
#ifdef ZTS
- ts_allocate_fast_id(&gc_globals_id, &gc_globals_offset, sizeof(zend_gc_globals), (ts_allocate_ctor) gc_globals_ctor_ex, (ts_allocate_dtor) root_buffer_dtor);
+ ts_allocate_tls_id(&gc_globals_id, gc_globals_tls_addr, sizeof(zend_gc_globals), (ts_allocate_ctor) gc_globals_ctor_ex, (ts_allocate_dtor) root_buffer_dtor);
#else
gc_globals_ctor_ex(&gc_globals);
#endif
@@ -2322,13 +2322,6 @@ void gc_bench_print(void)
}
#endif
-#ifdef ZTS
-size_t zend_gc_globals_size(void)
-{
- return sizeof(zend_gc_globals);
-}
-#endif
-
static ZEND_FUNCTION(gc_destructor_fiber)
{
uint32_t idx, end;
diff --git a/Zend/zend_gc.h b/Zend/zend_gc.h
index b72b90ccd5e..55b12070b99 100644
--- a/Zend/zend_gc.h
+++ b/Zend/zend_gc.h
@@ -69,10 +69,6 @@ void gc_globals_ctor(void);
void gc_globals_dtor(void);
void gc_reset(void);
-#ifdef ZTS
-size_t zend_gc_globals_size(void);
-#endif
-
#define GC_REMOVE_FROM_BUFFER(p) do { \
zend_refcounted *_p = (zend_refcounted*)(p); \
if (GC_TYPE_INFO(_p) & GC_INFO_MASK) { \
diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h
index 419f9cc07c7..ff025343b7a 100644
--- a/Zend/zend_globals.h
+++ b/Zend/zend_globals.h
@@ -52,8 +52,6 @@
BEGIN_EXTERN_C()
ZEND_API extern int compiler_globals_id;
ZEND_API extern int executor_globals_id;
-ZEND_API extern size_t compiler_globals_offset;
-ZEND_API extern size_t executor_globals_offset;
END_EXTERN_C()
#endif
@@ -342,9 +340,11 @@ struct _zend_executor_globals {
};
#ifdef ZTS
-/* Compile-time offsets of the hot globals, in a reserved region just before *_tsrm_ls_cache. */
-# define ZEND_CG_OFFSET (-(ptrdiff_t) TSRM_ALIGNED_SIZE(sizeof(zend_compiler_globals)))
-# define ZEND_EG_OFFSET (ZEND_CG_OFFSET - (ptrdiff_t) TSRM_ALIGNED_SIZE(sizeof(zend_executor_globals)))
+struct _zend_tsrm_ls_cache {
+ void *cache;
+ zend_executor_globals eg;
+ zend_compiler_globals cg;
+};
#endif
#define EG_FLAGS_INITIAL (0)
diff --git a/Zend/zend_globals_macros.h b/Zend/zend_globals_macros.h
index adb3913ece7..684ed696adf 100644
--- a/Zend/zend_globals_macros.h
+++ b/Zend/zend_globals_macros.h
@@ -30,7 +30,7 @@ BEGIN_EXTERN_C()
/* Compiler */
#ifdef ZTS
-# define CG(v) ZEND_TSRMG_FAST(ZEND_CG_OFFSET, zend_compiler_globals *, v)
+# define CG(v) ZEND_TSRMG_DIRECT(compiler_globals_id, zend_compiler_globals *, cg, v)
#else
# define CG(v) (compiler_globals.v)
extern ZEND_API struct _zend_compiler_globals compiler_globals;
@@ -40,7 +40,7 @@ ZEND_API int zendparse(void);
/* Executor */
#ifdef ZTS
-# define EG(v) ZEND_TSRMG_FAST(ZEND_EG_OFFSET, zend_executor_globals *, v)
+# define EG(v) ZEND_TSRMG_DIRECT(executor_globals_id, zend_executor_globals *, eg, v)
#else
# define EG(v) (executor_globals.v)
extern ZEND_API zend_executor_globals executor_globals;
@@ -49,15 +49,15 @@ extern ZEND_API zend_executor_globals executor_globals;
/* Language Scanner */
#ifdef ZTS
extern ZEND_API ts_rsrc_id language_scanner_globals_id;
-# if defined(ZEND_WIN32) && !defined(LIBZEND_EXPORTS)
-# define LANG_SCNG(v) TSRMG(language_scanner_globals_id, zend_php_scanner_globals *, v)
-# else
+# ifdef ZEND_TLS_DIRECT
# ifdef ZEND_WIN32
extern TSRM_TLS zend_php_scanner_globals language_scanner_globals;
# else
-extern ZEND_API TSRM_TLS TSRM_TLS_MODEL_ATTR zend_php_scanner_globals language_scanner_globals;
+extern ZEND_TLS_API TSRM_TLS TSRM_TLS_MODEL_ATTR zend_php_scanner_globals language_scanner_globals;
# endif
# define LANG_SCNG(v) (language_scanner_globals.v)
+# else
+# define LANG_SCNG(v) TSRMG(language_scanner_globals_id, zend_php_scanner_globals *, v)
# endif
#else
extern ZEND_API zend_php_scanner_globals language_scanner_globals;
diff --git a/ext/opcache/jit/tls/testing/user.c b/ext/opcache/jit/tls/testing/user.c
index 19e9f06c080..446b876033d 100644
--- a/ext/opcache/jit/tls/testing/user.c
+++ b/ext/opcache/jit/tls/testing/user.c
@@ -3,8 +3,6 @@
#include "../zend_jit_tls.h"
-TSRMLS_MAIN_CACHE_EXTERN()
-
int test(void)
{
size_t tcb_offset = 0;
@@ -12,7 +10,7 @@ int test(void)
size_t module_offset = -1;
/* Ensure the slot is allocated */
- _tsrm_ls_cache = NULL;
+ void *cache = &_tsrm_ls_cache;
zend_result result = zend_jit_resolve_tsrm_ls_cache_offsets(
&tcb_offset, &module_index, &module_offset);
@@ -24,5 +22,5 @@ int test(void)
return 0;
}
- return zend_jit_tsrm_ls_cache_address(tcb_offset, module_index, module_offset) == &_tsrm_ls_cache;
+ return zend_jit_tsrm_ls_cache_address(tcb_offset, module_index, module_offset) == cache;
}
diff --git a/ext/opcache/jit/tls/zend_jit_tls_win.c b/ext/opcache/jit/tls/zend_jit_tls_win.c
index 5646f3dcba0..9bd79571eea 100644
--- a/ext/opcache/jit/tls/zend_jit_tls_win.c
+++ b/ext/opcache/jit/tls/zend_jit_tls_win.c
@@ -33,30 +33,20 @@ zend_result zend_jit_resolve_tsrm_ls_cache_offsets(
size_t *module_index,
size_t *module_offset
) {
- /* To find offset of "_tsrm_ls_cache" in TLS segment we perform a linear scan of local TLS memory */
- /* Probably, it might be better solution */
+ /* Offset of _tsrm_ls_cache within this module's TLS block. */
#ifdef _WIN64
void ***tls_mem = ((void****)__readgsqword(0x58))[_tls_index];
#else
void ***tls_mem = ((void****)__readfsdword(0x2c))[_tls_index];
#endif
- void *val = _tsrm_ls_cache;
- size_t offset = 0;
size_t size = (char*)&_tls_end - (char*)&_tls_start;
-
- while (offset < size) {
- if (*tls_mem == val) {
- *module_index = _tls_index * sizeof(void*);
- *module_offset = offset;
- return SUCCESS;
- }
- tls_mem++;
- offset += sizeof(void*);
- }
+ size_t offset = (size_t)((char*)&_tsrm_ls_cache - (char*)tls_mem);
if (offset >= size) {
zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: offset >= size");
}
- return FAILURE;
+ *module_index = _tls_index * sizeof(void*);
+ *module_offset = offset;
+ return SUCCESS;
}
diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c
index 66b1b6a0c7b..b8f83813432 100644
--- a/ext/opcache/jit/zend_jit_ir.c
+++ b/ext/opcache/jit/zend_jit_ir.c
@@ -204,16 +204,16 @@ static size_t tsrm_tls_index = -1;
static size_t tsrm_tls_offset = -1;
# define EG_TLS_OFFSET(field) \
- (executor_globals_offset + offsetof(zend_executor_globals, field))
+ (offsetof(zend_tsrm_ls_cache, eg) + offsetof(zend_executor_globals, field))
# define CG_TLS_OFFSET(field) \
- (compiler_globals_offset + offsetof(zend_compiler_globals, field))
+ (offsetof(zend_tsrm_ls_cache, cg) + offsetof(zend_compiler_globals, field))
# define jit_EG(_field) \
- ir_ADD_OFFSET(jit_TLS(jit), EG_TLS_OFFSET(_field))
+ jit_TLS_ADDR(jit, EG_TLS_OFFSET(_field))
# define jit_CG(_field) \
- ir_ADD_OFFSET(jit_TLS(jit), CG_TLS_OFFSET(_field))
+ jit_TLS_ADDR(jit, CG_TLS_OFFSET(_field))
#else
@@ -504,20 +504,24 @@ static const char* zend_reg_name(int8_t reg)
#ifdef ZTS
static void * ZEND_FASTCALL zend_jit_get_tsrm_ls_cache(void)
{
- return _tsrm_ls_cache;
+ return &_tsrm_ls_cache;
}
-static ir_ref jit_TLS(zend_jit_ctx *jit)
+static ir_ref jit_TLS_ADDR(zend_jit_ctx *jit, size_t offset)
{
ZEND_ASSERT(jit->ctx.control);
+ if (tsrm_ls_cache_tcb_offset) {
+ return ir_TLS_ADDR(-1, tsrm_ls_cache_tcb_offset + offset);
+ }
+
if (jit->tls) {
- /* Emit "TLS" once for basic block */
+ /* Reuse the TLS lookup within a basic block. */
ir_insn *insn;
ir_ref ref = jit->ctx.control;
while (1) {
if (ref == jit->tls) {
- return jit->tls;
+ return ir_ADD_OFFSET(jit->tls, offset);
}
insn = &jit->ctx.ir_base[ref];
if (insn->op >= IR_START || insn->op == IR_CALL) {
@@ -527,9 +531,7 @@ static ir_ref jit_TLS(zend_jit_ctx *jit)
}
}
- if (tsrm_ls_cache_tcb_offset == 0 && tsrm_tls_index == -1) {
- jit->tls = ir_CALL(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_get_tsrm_ls_cache));
- } else {
+ if (tsrm_tls_index != -1) {
# ifdef ZEND_OPCACHE_SHM_REATTACHMENT
/* Different processes may load TLS variables in a different order, so
* they may have a different module index. Fetch the module index at
@@ -546,15 +548,15 @@ static ir_ref jit_TLS(zend_jit_ctx *jit)
ir_ref tls_array = ir_TLS(-1, offset);
ir_ref index = ir_LOAD_A(ir_CONST_ADDR(&tsrm_tls_index));
- jit->tls = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(ir_ADD_A(tls_array, index)), tsrm_tls_offset));
+ jit->tls = ir_ADD_OFFSET(ir_LOAD_A(ir_ADD_A(tls_array, index)), tsrm_tls_offset);
# else
- jit->tls = ir_TLS(
- tsrm_ls_cache_tcb_offset ? tsrm_ls_cache_tcb_offset : tsrm_tls_index,
- tsrm_ls_cache_tcb_offset ? IR_NULL : tsrm_tls_offset);
+ jit->tls = ir_TLS_ADDR(tsrm_tls_index, tsrm_tls_offset);
# endif
+ } else {
+ jit->tls = ir_CALL(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_get_tsrm_ls_cache));
}
- return jit->tls;
+ return ir_ADD_OFFSET(jit->tls, offset);
}
#endif
diff --git a/main/debug_gdb_scripts.c b/main/debug_gdb_scripts.c
index 0fb9450388d..57d204b8d92 100644
Binary files a/main/debug_gdb_scripts.c and b/main/debug_gdb_scripts.c differ
diff --git a/main/main.c b/main/main.c
index 1e4acfc8aa9..ee7d1cca69b 100644
--- a/main/main.c
+++ b/main/main.c
@@ -2797,15 +2797,14 @@ PHPAPI zend_result php_lint_script(zend_file_handle *file)
/* {{{ php_reserve_tsrm_memory */
PHPAPI void php_reserve_tsrm_memory(void)
{
+ /* CG/EG/GC globals live in native __thread storage and need no
+ * reserved TSRM space. */
tsrm_reserve(
- TSRM_ALIGNED_SIZE(sizeof(zend_compiler_globals)) +
- TSRM_ALIGNED_SIZE(sizeof(zend_executor_globals)) +
TSRM_ALIGNED_SIZE(sizeof(zend_ini_scanner_globals)) +
TSRM_ALIGNED_SIZE(sizeof(virtual_cwd_globals)) +
#ifdef ZEND_SIGNALS
TSRM_ALIGNED_SIZE(sizeof(zend_signal_globals_t)) +
#endif
- TSRM_ALIGNED_SIZE(zend_gc_globals_size()) +
TSRM_ALIGNED_SIZE(sizeof(php_core_globals)) +
TSRM_ALIGNED_SIZE(sizeof(sapi_globals_struct)) +
TSRM_ALIGNED_SIZE(sizeof(zend_accel_globals)) +
@@ -2821,10 +2820,6 @@ PHPAPI bool php_tsrm_startup_ex(int expected_threads)
{
bool ret = tsrm_startup(expected_threads, 1, 0, NULL);
php_reserve_tsrm_memory();
- /* Must cover the total size of every ZEND_*_OFFSET global, or the furthest underflows the block. */
- tsrm_reserve_fast_front(
- TSRM_ALIGNED_SIZE(sizeof(zend_compiler_globals)) +
- TSRM_ALIGNED_SIZE(sizeof(zend_executor_globals)));
(void)ts_resource(0);
return ret;
}