Skip to content

Commit 6afa98f

Browse files
committed
embed EG()/CG() into _tsrm_ls_cache
1 parent a4ec0fc commit 6afa98f

6 files changed

Lines changed: 76 additions & 97 deletions

File tree

TSRM/TSRM.h

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -177,17 +177,18 @@ TSRM_API bool tsrm_is_managed_thread(void);
177177
#define TSRMG_BULK_STATIC(id, type) ((type) (*((void ***) TSRMLS_CACHE))[TSRM_UNSHUFFLE_RSRC_ID(id)])
178178
#define TSRMG_FAST_STATIC(offset, type, element) (TSRMG_FAST_BULK_STATIC(offset, type)->element)
179179
#define TSRMG_FAST_BULK_STATIC(offset, type) ((type) (((char*) TSRMLS_CACHE)+(offset)))
180+
struct _zend_tsrm_ls_cache;
180181
#ifdef __cplusplus
181-
#define TSRMLS_MAIN_CACHE_EXTERN() extern "C" { extern TSRM_TLS void *TSRMLS_CACHE TSRM_TLS_MODEL_ATTR; }
182-
#define TSRMLS_CACHE_EXTERN() extern "C" { extern TSRM_TLS void *TSRMLS_CACHE; }
182+
#define TSRMLS_MAIN_CACHE_EXTERN() extern "C" { extern TSRM_TLS struct _zend_tsrm_ls_cache _tsrm_ls_cache TSRM_TLS_MODEL_ATTR; }
183+
#define TSRMLS_CACHE_EXTERN() extern "C" { extern TSRM_TLS struct _zend_tsrm_ls_cache _tsrm_ls_cache; }
183184
#else
184-
#define TSRMLS_MAIN_CACHE_EXTERN() extern TSRM_TLS void *TSRMLS_CACHE TSRM_TLS_MODEL_ATTR;
185-
#define TSRMLS_CACHE_EXTERN() extern TSRM_TLS void *TSRMLS_CACHE;
185+
#define TSRMLS_MAIN_CACHE_EXTERN() extern TSRM_TLS struct _zend_tsrm_ls_cache _tsrm_ls_cache TSRM_TLS_MODEL_ATTR;
186+
#define TSRMLS_CACHE_EXTERN() extern TSRM_TLS struct _zend_tsrm_ls_cache _tsrm_ls_cache;
186187
#endif
187-
#define TSRMLS_MAIN_CACHE_DEFINE() TSRM_TLS void *TSRMLS_CACHE TSRM_TLS_MODEL_ATTR = NULL;
188-
#define TSRMLS_CACHE_DEFINE() TSRM_TLS void *TSRMLS_CACHE = NULL;
188+
#define TSRMLS_MAIN_CACHE_DEFINE()
189+
#define TSRMLS_CACHE_DEFINE()
189190
#define TSRMLS_CACHE_UPDATE() TSRMLS_CACHE = tsrm_get_ls_cache()
190-
#define TSRMLS_CACHE _tsrm_ls_cache
191+
#define TSRMLS_CACHE (*(void **) &_tsrm_ls_cache)
191192

192193
#ifdef __cplusplus
193194
}

Zend/zend.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,18 +52,16 @@ static bool startup_done = false;
5252
#ifdef ZTS
5353
ZEND_API int compiler_globals_id;
5454
ZEND_API int executor_globals_id;
55-
ZEND_TLS_API TSRM_TLS TSRM_TLS_MODEL_ATTR zend_executor_globals executor_globals_tls;
56-
ZEND_TLS_API TSRM_TLS TSRM_TLS_MODEL_ATTR zend_compiler_globals compiler_globals_tls;
55+
ZEND_TLS_API TSRM_TLS TSRM_TLS_MODEL_ATTR zend_tsrm_ls_cache _tsrm_ls_cache = {0};
5756
/* ts_allocate_tls_id takes a callback so each thread resolves its own block.
5857
* A plain &..._tls would capture only the registering thread's address. */
59-
static void *executor_globals_tls_addr(void) { return &executor_globals_tls; }
60-
static void *compiler_globals_tls_addr(void) { return &compiler_globals_tls; }
58+
static void *executor_globals_tls_addr(void) { return &_tsrm_ls_cache.eg; }
59+
static void *compiler_globals_tls_addr(void) { return &_tsrm_ls_cache.cg; }
6160
static HashTable *global_function_table = NULL;
6261
static HashTable *global_class_table = NULL;
6362
static HashTable *global_constants_table = NULL;
6463
static HashTable *global_auto_globals_table = NULL;
6564
static HashTable *global_persistent_list = NULL;
66-
TSRMLS_MAIN_CACHE_DEFINE()
6765
# define GLOBAL_FUNCTION_TABLE global_function_table
6866
# define GLOBAL_CLASS_TABLE global_class_table
6967
# define GLOBAL_CONSTANTS_TABLE global_constants_table
@@ -805,6 +803,7 @@ static void compiler_globals_dtor(zend_compiler_globals *compiler_globals) /* {{
805803

806804
static void executor_globals_ctor(zend_executor_globals *executor_globals) /* {{{ */
807805
{
806+
_tsrm_ls_cache.self = &_tsrm_ls_cache;
808807
zend_startup_constants();
809808
zend_copy_constants(executor_globals->zend_constants, GLOBAL_CONSTANTS_TABLE);
810809
zend_init_rsrc_plist();

Zend/zend_globals.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,15 @@ struct _zend_executor_globals {
327327
void *reserved[ZEND_MAX_RESERVED_RESOURCES];
328328
};
329329

330+
#ifdef ZTS
331+
struct _zend_tsrm_ls_cache {
332+
void *cache;
333+
void *self;
334+
zend_executor_globals eg;
335+
zend_compiler_globals cg;
336+
};
337+
#endif
338+
330339
#define EG_FLAGS_INITIAL (0)
331340
#define EG_FLAGS_IN_SHUTDOWN (1<<0)
332341
#define EG_FLAGS_OBJECT_STORE_NO_REUSE (1<<1)

Zend/zend_globals_macros.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,15 @@ typedef struct _zend_ini_scanner_globals zend_ini_scanner_globals;
3838

3939
BEGIN_EXTERN_C()
4040

41+
#ifdef ZTS
42+
typedef struct _zend_tsrm_ls_cache zend_tsrm_ls_cache;
43+
extern ZEND_TLS_API TSRM_TLS TSRM_TLS_MODEL_ATTR zend_tsrm_ls_cache _tsrm_ls_cache;
44+
#endif
45+
4146
/* Compiler */
4247
#ifdef ZTS
4348
# ifdef ZEND_TLS_DIRECT
44-
extern ZEND_TLS_API TSRM_TLS TSRM_TLS_MODEL_ATTR zend_compiler_globals compiler_globals_tls;
45-
# define CG(v) (compiler_globals_tls.v)
49+
# define CG(v) (_tsrm_ls_cache.cg.v)
4650
# else
4751
# define CG(v) ZEND_TSRMG(compiler_globals_id, zend_compiler_globals *, v)
4852
# endif
@@ -56,8 +60,7 @@ ZEND_API int zendparse(void);
5660
/* Executor */
5761
#ifdef ZTS
5862
# ifdef ZEND_TLS_DIRECT
59-
extern ZEND_TLS_API TSRM_TLS TSRM_TLS_MODEL_ATTR zend_executor_globals executor_globals_tls;
60-
# define EG(v) (executor_globals_tls.v)
63+
# define EG(v) (_tsrm_ls_cache.eg.v)
6164
# else
6265
# define EG(v) ZEND_TSRMG(executor_globals_id, zend_executor_globals *, v)
6366
# endif

ext/opcache/jit/ir/ir_aarch64.dasc

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5868,8 +5868,6 @@ static void ir_emit_tls(ir_ctx *ctx, ir_ref def, ir_insn *insn)
58685868
| ldr Rx(reg), [Rx(reg), #insn->op3]
58695869
|| }
58705870
||# else
5871-
|| /* op2 == 0 with no index requests the bare thread pointer (used to form
5872-
|| * &EG/&CG with an add); a real TLS var never sits at tprel offset 0. */
58735871
|| if (insn->op2 != 0 || insn->op3 != IR_NULL) {
58745872
||//??? IR_ASSERT(insn->op2 <= LDR_STR_PIMM64);
58755873
| ldr Rx(reg), [Rx(reg), #insn->op2]

ext/opcache/jit/zend_jit_ir.c

Lines changed: 48 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -201,35 +201,21 @@ static uint32_t default_mflags = 0;
201201
static bool delayed_call_chain = false; // TODO: remove this var (use jit->delayed_call_level) ???
202202

203203
#ifdef ZTS
204-
static size_t eg_tls_tcb_offset = 0;
205-
static size_t cg_tls_tcb_offset = 0;
206-
/* gottpoff yields the offset from the %fs-based thread pointer that ir_TLS(0)
207-
* loads. */
208-
# if defined(__ELF__) && defined(__x86_64__) && defined(__GNUC__) && !defined(TSRM_TLS_MODEL_DEFAULT)
209-
# define ZEND_JIT_TLS_TCB_OFFSET(sym) __extension__({ \
210-
size_t _off; \
211-
__asm__ ("movq " #sym "@gottpoff(%%rip),%0" : "=r" (_off)); \
212-
_off; \
213-
})
214-
# elif defined(__ELF__) && defined(__aarch64__) && !defined(__APPLE__) && \
215-
(defined(__GNUC__) || defined(__clang__))
216-
/* The TLS variable sits at a fixed offset from tpidr_el0 (the thread pointer
217-
* the JIT reads with mrs); compute it once on the main thread. Subtracting the
218-
* thread pointer is model-independent (works for both local- and initial-exec)
219-
* and matches tsrm_get_ls_cache_tcb_offset()'s tprel reasoning. */
220-
# define ZEND_JIT_TLS_TCB_OFFSET(sym) __extension__({ \
221-
char *_tp; \
222-
__asm__ ("mrs %0, tpidr_el0" : "=r" (_tp)); \
223-
(size_t)((char*)&(sym) - _tp); \
224-
})
225-
# else
226-
# define ZEND_JIT_TLS_TCB_OFFSET(sym) ((size_t)0)
227-
# endif
204+
static size_t tsrm_ls_cache_tcb_offset = 0;
205+
static size_t tsrm_tls_index = -1;
206+
static size_t tsrm_tls_offset = -1;
207+
208+
# define EG_TLS_OFFSET(field) \
209+
(tsrm_ls_cache_tcb_offset + offsetof(zend_tsrm_ls_cache, eg) + offsetof(zend_executor_globals, field))
210+
211+
# define CG_TLS_OFFSET(field) \
212+
(tsrm_ls_cache_tcb_offset + offsetof(zend_tsrm_ls_cache, cg) + offsetof(zend_compiler_globals, field))
228213

229214
# define jit_EG(_field) \
230-
ir_ADD_OFFSET(jit_EG_base(jit), offsetof(zend_executor_globals, _field))
215+
ir_ADD_OFFSET(jit_TLS(jit), EG_TLS_OFFSET(_field))
216+
231217
# define jit_CG(_field) \
232-
ir_ADD_OFFSET(jit_CG_base(jit), offsetof(zend_compiler_globals, _field))
218+
ir_ADD_OFFSET(jit_TLS(jit), CG_TLS_OFFSET(_field))
233219

234220
#else
235221

@@ -312,9 +298,7 @@ typedef struct _zend_jit_ctx {
312298
uint32_t delayed_call_level;
313299
int b; /* current basic block number or -1 */
314300
#ifdef ZTS
315-
ir_ref tp; /* cached thread pointer for &EG/&CG */
316-
ir_ref eg_tls; /* cached base of __thread executor_globals_tls */
317-
ir_ref cg_tls; /* cached base of __thread compiler_globals_tls */
301+
ir_ref tls;
318302
#endif
319303
ir_ref fp;
320304
ir_ref poly_func_ref; /* restored from parent trace snapshot */
@@ -505,60 +489,41 @@ static const char* zend_reg_name(int8_t reg)
505489
/* IR helpers */
506490

507491
#ifdef ZTS
508-
static void * ZEND_FASTCALL zend_jit_get_eg_tls(void)
509-
{
510-
return &executor_globals_tls;
511-
}
512-
static void * ZEND_FASTCALL zend_jit_get_cg_tls(void)
492+
static void * ZEND_FASTCALL zend_jit_get_tsrm_ls_cache(void)
513493
{
514-
return &compiler_globals_tls;
494+
return &_tsrm_ls_cache;
515495
}
516496

517-
/* Walk the control chain back from the current point: reuse the cached ref if we
518-
* reach it (it still dominates here), but bail at a block start or a call, since
519-
* the cached value lives in a caller-saved register that a call would clobber. */
520-
static ir_ref jit_tls_reuse(zend_jit_ctx *jit, ir_ref cached)
497+
static ir_ref jit_TLS(zend_jit_ctx *jit)
521498
{
522-
ir_ref ref = jit->ctx.control;
499+
ZEND_ASSERT(jit->ctx.control);
500+
if (jit->tls) {
501+
/* Emit "TLS" once for basic block */
502+
ir_insn *insn;
503+
ir_ref ref = jit->ctx.control;
523504

524-
while (cached) {
525-
if (ref == cached) {
526-
return cached;
527-
}
528-
ir_insn *insn = &jit->ctx.ir_base[ref];
529-
if (insn->op >= IR_START || insn->op == IR_CALL) {
530-
break;
505+
while (1) {
506+
if (ref == jit->tls) {
507+
return jit->tls;
508+
}
509+
insn = &jit->ctx.ir_base[ref];
510+
if (insn->op >= IR_START || insn->op == IR_CALL) {
511+
break;
512+
}
513+
ref = insn->op1;
531514
}
532-
ref = insn->op1;
533515
}
534-
return IR_UNUSED;
535-
}
536516

537-
/* Thread pointer, cached per basic block, used to form &EG/&CG with an add. */
538-
static ir_ref jit_TP(zend_jit_ctx *jit)
539-
{
540-
ZEND_ASSERT(jit->ctx.control);
541-
if (!jit_tls_reuse(jit, jit->tp)) {
542-
jit->tp = ir_TLS(0, IR_NULL);
517+
if (tsrm_ls_cache_tcb_offset == 0 && tsrm_tls_index == -1) {
518+
jit->tls = ir_CALL(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_get_tsrm_ls_cache));
519+
} else if (tsrm_ls_cache_tcb_offset) {
520+
jit->tls = ir_TLS(0, IR_NULL);
521+
} else {
522+
jit->tls = ir_TLS(tsrm_tls_index, tsrm_tls_offset + offsetof(zend_tsrm_ls_cache, self));
543523
}
544-
return jit->tp;
545-
}
546524

547-
/* Used where the TCB offset is unknown: resolve the base via a cached call. */
548-
static ir_ref jit_GLOBALS_TLS_call(zend_jit_ctx *jit, ir_ref *cache, const void *fn)
549-
{
550-
ZEND_ASSERT(jit->ctx.control);
551-
if (!jit_tls_reuse(jit, *cache)) {
552-
*cache = ir_CALL(IR_ADDR, ir_CONST_FC_FUNC(fn));
553-
}
554-
return *cache;
525+
return jit->tls;
555526
}
556-
# define jit_EG_base(jit) (eg_tls_tcb_offset \
557-
? ir_ADD_OFFSET(jit_TP(jit), eg_tls_tcb_offset) \
558-
: jit_GLOBALS_TLS_call((jit), &(jit)->eg_tls, zend_jit_get_eg_tls))
559-
# define jit_CG_base(jit) (cg_tls_tcb_offset \
560-
? ir_ADD_OFFSET(jit_TP(jit), cg_tls_tcb_offset) \
561-
: jit_GLOBALS_TLS_call((jit), &(jit)->cg_tls, zend_jit_get_cg_tls))
562527
#endif
563528

564529
static ir_ref jit_CONST_ADDR(zend_jit_ctx *jit, uintptr_t addr)
@@ -2855,9 +2820,7 @@ static void zend_jit_init_ctx(zend_jit_ctx *jit, uint32_t flags)
28552820
delayed_call_chain = false;
28562821
jit->b = -1;
28572822
#ifdef ZTS
2858-
jit->tp = IR_UNUSED;
2859-
jit->eg_tls = IR_UNUSED;
2860-
jit->cg_tls = IR_UNUSED;
2823+
jit->tls = IR_UNUSED;
28612824
#endif
28622825
jit->fp = IR_UNUSED;
28632826
jit->poly_func_ref = IR_UNUSED;
@@ -3251,8 +3214,7 @@ static void zend_jit_setup_disasm(void)
32513214

32523215
REGISTER_DATA(CG(map_ptr_base));
32533216
#else /* ZTS */
3254-
REGISTER_HELPER(zend_jit_get_eg_tls);
3255-
REGISTER_HELPER(zend_jit_get_cg_tls);
3217+
REGISTER_HELPER(zend_jit_get_tsrm_ls_cache);
32563218
#endif
32573219
#endif
32583220
}
@@ -3463,8 +3425,15 @@ static void zend_jit_setup(bool reattached)
34633425
#endif
34643426

34653427
#ifdef ZTS
3466-
eg_tls_tcb_offset = ZEND_JIT_TLS_TCB_OFFSET(executor_globals_tls);
3467-
cg_tls_tcb_offset = ZEND_JIT_TLS_TCB_OFFSET(compiler_globals_tls);
3428+
zend_result result = zend_jit_resolve_tsrm_ls_cache_offsets(
3429+
&tsrm_ls_cache_tcb_offset,
3430+
&tsrm_tls_index,
3431+
&tsrm_tls_offset
3432+
);
3433+
if (result == FAILURE) {
3434+
zend_accel_error(ACCEL_LOG_INFO,
3435+
"Could not get _tsrm_ls_cache offsets, will fallback to runtime resolution");
3436+
}
34683437
#endif
34693438

34703439
#if !defined(ZEND_WIN32) && !defined(IR_TARGET_AARCH64)

0 commit comments

Comments
 (0)