diff --git a/TSRM/TSRM.c b/TSRM/TSRM.c index e99993204b6f..fe5ca8aa99d9 100644 --- a/TSRM/TSRM.c +++ b/TSRM/TSRM.c @@ -42,6 +42,8 @@ typedef struct { ts_allocate_ctor ctor; ts_allocate_dtor dtor; size_t fast_offset; + /* When set, storage comes from __thread memory instead of being allocated by TSRM. */ + void *(*tls_addr)(void); int done; } tsrm_resource_type; @@ -163,14 +165,19 @@ TSRM_API bool tsrm_startup(int expected_threads, int expected_resources, int deb static void ts_free_resources(tsrm_tls_entry *thread_resources) { + bool own_thread = thread_resources->thread_id == tsrm_thread_id(); + /* Need to destroy in reverse order to respect dependencies. */ for (int i = thread_resources->count - 1; i >= 0; i--) { if (!resource_types_table[i].done) { + if (resource_types_table[i].tls_addr && !own_thread) { + continue; + } if (resource_types_table[i].dtor) { resource_types_table[i].dtor(thread_resources->storage[i]); } - if (!resource_types_table[i].fast_offset) { + if (!resource_types_table[i].fast_offset && !resource_types_table[i].tls_addr) { free(thread_resources->storage[i]); } } @@ -256,7 +263,10 @@ static void tsrm_update_active_threads(void) p->storage = (void *) realloc(p->storage, sizeof(void *)*id_count); for (j=p->count; jthread_id == tsrm_thread_id()); + p->storage[j] = resource_types_table[j].tls_addr(); + } else if (resource_types_table[j].fast_offset) { p->storage[j] = (void *) (((char*)p) + resource_types_table[j].fast_offset); } else { p->storage[j] = (void *) malloc(resource_types_table[j].size); @@ -301,6 +311,7 @@ TSRM_API ts_rsrc_id ts_allocate_id(ts_rsrc_id *rsrc_id, size_t size, ts_allocate resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].ctor = ctor; resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].dtor = dtor; resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].fast_offset = 0; + resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].tls_addr = NULL; resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].done = 0; tsrm_update_active_threads(); @@ -359,6 +370,7 @@ TSRM_API ts_rsrc_id ts_allocate_fast_id(ts_rsrc_id *rsrc_id, size_t *offset, siz resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].ctor = ctor; resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].dtor = dtor; resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].fast_offset = *offset; + resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].tls_addr = NULL; resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].done = 0; tsrm_update_active_threads(); @@ -368,6 +380,41 @@ TSRM_API ts_rsrc_id ts_allocate_fast_id(ts_rsrc_id *rsrc_id, size_t *offset, siz 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) +{/*{{{*/ + TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Obtaining a new TLS resource id, %d bytes", size)); + + tsrm_mutex_lock(tsmm_mutex); + + *rsrc_id = TSRM_SHUFFLE_RSRC_ID(id_count++); + + if (resource_types_table_size < id_count) { + tsrm_resource_type *_tmp; + _tmp = (tsrm_resource_type *) realloc(resource_types_table, sizeof(tsrm_resource_type)*id_count); + if (!_tmp) { + TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Unable to allocate storage for resource")); + *rsrc_id = 0; + tsrm_mutex_unlock(tsmm_mutex); + return 0; + } + resource_types_table = _tmp; + resource_types_table_size = id_count; + } + resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].size = size; + resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].ctor = ctor; + resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].dtor = dtor; + resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].fast_offset = 0; + resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].tls_addr = tls_addr; + resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].done = 0; + + tsrm_update_active_threads(); + tsrm_mutex_unlock(tsmm_mutex); + + TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Successfully allocated new TLS resource id %d", *rsrc_id)); + return *rsrc_id; +}/*}}}*/ + static void set_thread_local_storage_resource_to(tsrm_tls_entry *thread_resource) { tsrm_tls_set(thread_resource); @@ -397,7 +444,9 @@ static void allocate_new_resource(tsrm_tls_entry **thread_resources_ptr, THREAD_ if (resource_types_table[i].done) { (*thread_resources_ptr)->storage[i] = NULL; } else { - if (resource_types_table[i].fast_offset) { + if (resource_types_table[i].tls_addr) { + (*thread_resources_ptr)->storage[i] = resource_types_table[i].tls_addr(); + } else if (resource_types_table[i].fast_offset) { (*thread_resources_ptr)->storage[i] = (void *) (((char*)(*thread_resources_ptr)) + resource_types_table[i].fast_offset); } else { (*thread_resources_ptr)->storage[i] = (void *) malloc(resource_types_table[i].size); @@ -486,6 +535,7 @@ TSRM_API void *ts_resource_ex(ts_rsrc_id id, THREAD_T *th_id) * use the global pointer, we need to setup the global pointer temporarily here. */ set_thread_local_storage_resource_to(thread_resources); /* Free up the old resource from the old thread instance */ + thread_resources->thread_id = 0; ts_free_resources(thread_resources); free(thread_resources); /* Allocate a new resource at the same point in the linked list, and relink the next pointer */ @@ -559,7 +609,7 @@ void ts_free_id(ts_rsrc_id id) if (resource_types_table[rsrc_id].dtor) { resource_types_table[rsrc_id].dtor(p->storage[rsrc_id]); } - if (!resource_types_table[rsrc_id].fast_offset) { + if (!resource_types_table[rsrc_id].fast_offset && !resource_types_table[rsrc_id].tls_addr) { free(p->storage[rsrc_id]); } } @@ -773,7 +823,10 @@ TSRM_API void *tsrm_get_ls_cache(void) /* Returns offset of tsrm_ls_cache slot from Thread Control Block address */ TSRM_API size_t tsrm_get_ls_cache_tcb_offset(void) {/*{{{*/ -#if defined(__APPLE__) && defined(__x86_64__) +#if defined(TSRM_TLS_MODEL_GLOBAL_DYNAMIC) + /* No constant TCB offset under global-dynamic, can't use fast path */ + return 0; +#elif defined(__APPLE__) && defined(__x86_64__) // TODO: Implement support for fast JIT ZTS code ??? return 0; #elif defined(__x86_64__) && defined(__GNUC__) && !defined(__FreeBSD__) && \ diff --git a/TSRM/TSRM.h b/TSRM/TSRM.h index ea13552c8374..2bf84c0b6245 100644 --- a/TSRM/TSRM.h +++ b/TSRM/TSRM.h @@ -93,6 +93,8 @@ TSRM_API ts_rsrc_id ts_allocate_id(ts_rsrc_id *rsrc_id, size_t size, ts_allocate /* Fast resource in reserved (pre-allocated) space */ 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); +/* 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); /* fetches the requested resource for the current thread */ TSRM_API void *ts_resource_ex(ts_rsrc_id id, THREAD_T *th_id); @@ -155,9 +157,14 @@ TSRM_API bool tsrm_is_managed_thread(void); #if !__has_attribute(tls_model) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__MUSL__) || defined(__HAIKU__) # define TSRM_TLS_MODEL_ATTR # define TSRM_TLS_MODEL_DEFAULT -#elif __PIC__ -# define TSRM_TLS_MODEL_ATTR __attribute__((tls_model("initial-exec"))) -# define TSRM_TLS_MODEL_INITIAL_EXEC +#elif __PIC__ && !defined(__PIE__) +# if defined(TSRM_TLS_MODEL_USE_GLOBAL_DYNAMIC) +# define TSRM_TLS_MODEL_ATTR __attribute__((tls_model("global-dynamic"))) +# define TSRM_TLS_MODEL_GLOBAL_DYNAMIC +# else +# define TSRM_TLS_MODEL_ATTR __attribute__((tls_model("initial-exec"))) +# define TSRM_TLS_MODEL_INITIAL_EXEC +# endif #else # define TSRM_TLS_MODEL_ATTR __attribute__((tls_model("local-exec"))) # define TSRM_TLS_MODEL_LOCAL_EXEC @@ -175,17 +182,27 @@ 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))) +struct _zend_tsrm_ls_cache; +#if defined(ZEND_WIN32) && !defined(LIBZEND_EXPORTS) +/* Windows can't dllexport the TLS struct, so outside Zend each module + * keeps a per-module `void *` pointer and reaches EG/CG via the resource-id indirection. */ +# define ZEND_TSRMLS_CACHE_T void * +# define TSRMLS_MAIN_CACHE_DEFINE() TSRM_TLS void *_tsrm_ls_cache TSRM_TLS_MODEL_ATTR = NULL; +# define TSRMLS_CACHE_DEFINE() TSRM_TLS void *_tsrm_ls_cache = NULL; +#else +# define ZEND_TSRMLS_CACHE_T struct _zend_tsrm_ls_cache +# define TSRMLS_MAIN_CACHE_DEFINE() +# define TSRMLS_CACHE_DEFINE() +#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 } diff --git a/Zend/Zend.m4 b/Zend/Zend.m4 index d0c682e8e659..319ddca1e025 100644 --- a/Zend/Zend.m4 +++ b/Zend/Zend.m4 @@ -178,6 +178,11 @@ AC_MSG_RESULT([$ZEND_ZTS]) AS_VAR_IF([ZEND_ZTS], [yes], [ AC_DEFINE([ZTS], [1], [Define to 1 if thread safety (ZTS) is enabled.]) AS_VAR_APPEND([CFLAGS], [" -DZTS"]) + + dnl -mtls-size=12 drops the dead high-bits offset add from TLS access, + dnl valid while the thread-local block stays under 4 KiB. + AX_CHECK_COMPILE_FLAG([-mtls-size=12], + [AS_VAR_APPEND([CFLAGS], [" -mtls-size=12"])]) ]) AC_MSG_CHECKING([whether to enable Zend debugging]) diff --git a/Zend/zend.c b/Zend/zend.c index f16b1a30dbbc..6ab6ef74b5e4 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -52,14 +52,29 @@ 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}; +#if defined(_WIN64) && defined(ZEND_TLS_DIRECT) +/* Holds &_tsrm_ls_cache in a TEB TLS slot (filled by DllMain) so EG()/CG() reach it + * with a single gs:[] load rather than the 3-load __declspec(thread) lookup. */ +ZEND_TLS_API unsigned long zend_win_tsrm_cache_slot = 0; +ZEND_API void zend_win_tsrm_cache_init(bool alloc) +{ + if (alloc) { + zend_win_tsrm_cache_slot = TlsAlloc(); + ZEND_ASSERT(zend_win_tsrm_cache_slot < 64); /* must be a direct TEB TlsSlot */ + } + TlsSetValue(zend_win_tsrm_cache_slot, &_tsrm_ls_cache); +} +#endif +/* ts_allocate_tls_id takes a callback so each thread resolves its own block. + * A plain &..._tls 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 HashTable *global_function_table = NULL; static HashTable *global_class_table = NULL; static HashTable *global_constants_table = NULL; static HashTable *global_auto_globals_table = NULL; static HashTable *global_persistent_list = 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 @@ -801,6 +816,7 @@ static void compiler_globals_dtor(zend_compiler_globals *compiler_globals) /* {{ static void executor_globals_ctor(zend_executor_globals *executor_globals) /* {{{ */ { + _tsrm_ls_cache.self = &_tsrm_ls_cache; zend_startup_constants(); zend_copy_constants(executor_globals->zend_constants, GLOBAL_CONSTANTS_TABLE); zend_init_rsrc_plist(); @@ -1019,8 +1035,8 @@ void zend_startup(zend_utility_functions *utility_functions) /* {{{ */ zend_init_rsrc_list_dtors(); #ifdef ZTS - ts_allocate_fast_id(&compiler_globals_id, &compiler_globals_offset, sizeof(zend_compiler_globals), (ts_allocate_ctor) compiler_globals_ctor, (ts_allocate_dtor) compiler_globals_dtor); - ts_allocate_fast_id(&executor_globals_id, &executor_globals_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_fast_id(&language_scanner_globals_id, &language_scanner_globals_offset, sizeof(zend_php_scanner_globals), (ts_allocate_ctor) php_scanner_globals_ctor, NULL); 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); diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index 8257df32e831..346cf615c2f4 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -51,8 +51,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 @@ -329,6 +327,15 @@ struct _zend_executor_globals { void *reserved[ZEND_MAX_RESERVED_RESOURCES]; }; +#ifdef ZTS +struct _zend_tsrm_ls_cache { + void *cache; + void *self; + zend_executor_globals eg; + zend_compiler_globals cg; +}; +#endif + #define EG_FLAGS_INITIAL (0) #define EG_FLAGS_IN_SHUTDOWN (1<<0) #define EG_FLAGS_OBJECT_STORE_NO_REUSE (1<<1) diff --git a/Zend/zend_globals_macros.h b/Zend/zend_globals_macros.h index bde10a0989d1..57da0fb4cb60 100644 --- a/Zend/zend_globals_macros.h +++ b/Zend/zend_globals_macros.h @@ -26,11 +26,39 @@ typedef struct _zend_executor_globals zend_executor_globals; typedef struct _zend_php_scanner_globals zend_php_scanner_globals; typedef struct _zend_ini_scanner_globals zend_ini_scanner_globals; +#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 + BEGIN_EXTERN_C() +#ifdef ZTS +typedef struct _zend_tsrm_ls_cache zend_tsrm_ls_cache; +# ifdef ZEND_TLS_DIRECT +extern ZEND_TLS_API TSRM_TLS TSRM_TLS_MODEL_ATTR zend_tsrm_ls_cache _tsrm_ls_cache; +/* See zenc.c: zend_win_tsrm_cache_init */ +# if defined(_WIN64) +extern ZEND_TLS_API unsigned long zend_win_tsrm_cache_slot; +# define ZEND_TSRM_CACHE_PTR ((zend_tsrm_ls_cache*)__readgsqword(0x1480 + zend_win_tsrm_cache_slot * 8)) +# else +# define ZEND_TSRM_CACHE_PTR (&_tsrm_ls_cache) +# endif +# endif +#endif + /* Compiler */ #ifdef ZTS -# define CG(v) ZEND_TSRMG_FAST(compiler_globals_offset, zend_compiler_globals *, v) +# ifdef ZEND_TLS_DIRECT +# define CG(v) (ZEND_TSRM_CACHE_PTR->cg.v) +# else +# define CG(v) ZEND_TSRMG(compiler_globals_id, zend_compiler_globals *, v) +# endif #else # define CG(v) (compiler_globals.v) extern ZEND_API struct _zend_compiler_globals compiler_globals; @@ -40,7 +68,11 @@ ZEND_API int zendparse(void); /* Executor */ #ifdef ZTS -# define EG(v) ZEND_TSRMG_FAST(executor_globals_offset, zend_executor_globals *, v) +# ifdef ZEND_TLS_DIRECT +# define EG(v) (ZEND_TSRM_CACHE_PTR->eg.v) +# else +# define EG(v) ZEND_TSRMG(executor_globals_id, zend_executor_globals *, v) +# endif #else # define EG(v) (executor_globals.v) extern ZEND_API zend_executor_globals executor_globals; diff --git a/ext/opcache/jit/ir/ir_aarch64.dasc b/ext/opcache/jit/ir/ir_aarch64.dasc index fc4bb84f1e05..6eac958fd23f 100644 --- a/ext/opcache/jit/ir/ir_aarch64.dasc +++ b/ext/opcache/jit/ir/ir_aarch64.dasc @@ -5868,8 +5868,10 @@ static void ir_emit_tls(ir_ctx *ctx, ir_ref def, ir_insn *insn) | ldr Rx(reg), [Rx(reg), #insn->op3] || } ||# else +|| if (insn->op2 != 0 || insn->op3 != IR_NULL) { ||//??? IR_ASSERT(insn->op2 <= LDR_STR_PIMM64); -| ldr Rx(reg), [Rx(reg), #insn->op2] +| ldr Rx(reg), [Rx(reg), #insn->op2] +|| } ||# endif ||#endif if (IR_REG_SPILLED(ctx->regs[def][0])) { diff --git a/ext/opcache/jit/tls/zend_jit_tls_win.c b/ext/opcache/jit/tls/zend_jit_tls_win.c index 5646f3dcba0b..58fab12bf386 100644 --- a/ext/opcache/jit/tls/zend_jit_tls_win.c +++ b/ext/opcache/jit/tls/zend_jit_tls_win.c @@ -33,30 +33,21 @@ 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; } - 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 cf43d3ad840f..2fabc44bdcce 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -206,10 +206,10 @@ 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)) + (tsrm_ls_cache_tcb_offset + offsetof(zend_tsrm_ls_cache, eg) + offsetof(zend_executor_globals, field)) # define CG_TLS_OFFSET(field) \ - (compiler_globals_offset + offsetof(zend_compiler_globals, field)) + (tsrm_ls_cache_tcb_offset + 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)) @@ -491,7 +491,7 @@ 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) @@ -516,10 +516,10 @@ 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_ls_cache_tcb_offset) { + jit->tls = ir_TLS(0, IR_NULL); } 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(tsrm_tls_index, tsrm_tls_offset + offsetof(zend_tsrm_ls_cache, self)); } return jit->tls; diff --git a/sapi/apache2handler/config.m4 b/sapi/apache2handler/config.m4 index e335721f19e9..97044a6a3b5a 100644 --- a/sapi/apache2handler/config.m4 +++ b/sapi/apache2handler/config.m4 @@ -85,6 +85,10 @@ if test "$PHP_APXS2" != "no"; then LIBPHP_CFLAGS="-shared" PHP_SUBST([LIBPHP_CFLAGS]) + dnl httpd dlopen's libphp.so without linking against it, so _tsrm_ls_cache can't + dnl use initial-exec (overflows the static TLS surplus) + AS_VAR_APPEND([CFLAGS], [" -DTSRM_TLS_MODEL_USE_GLOBAL_DYNAMIC"]) + php_sapi_apache2handler_type=shared AS_CASE([$host_alias], [*aix*], [ diff --git a/win32/dllmain.c b/win32/dllmain.c index 168bef2baa22..bb9386b007ac 100644 --- a/win32/dllmain.c +++ b/win32/dllmain.c @@ -27,10 +27,22 @@ eq. initializing something before the DLL even is available to be called. */ +#if defined(_WIN64) && defined(ZTS) +ZEND_API void zend_win_tsrm_cache_init(bool alloc); +#endif + BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID dummy) { BOOL ret = TRUE; +#if defined(_WIN64) && defined(ZTS) + if (reason == DLL_PROCESS_ATTACH) { + zend_win_tsrm_cache_init(true); + } else if (reason == DLL_THREAD_ATTACH) { + zend_win_tsrm_cache_init(false); + } +#endif + #ifdef HAVE_LIBXML /* This imply that only LIBXML_STATIC_FOR_DLL is supported ATM. If that changes, this place will need some rework.