8000 Make functions, linked classes and their methods stored in opcache im… · php/php-src@056b551 · GitHub
[go: up one dir, main page]

Skip to content

Commit 056b551

Browse files
committed
Make functions, linked classes and their methods stored in opcache immutable.
1 parent 248c857 commit 056b551

21 files changed

+481
-230
lines changed

Zend/zend.c

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
#include "zend_smart_string.h"
3434
#include "zend_cpuinfo.h"
3535

36+
static zend_uintptr_t global_request_data_size = 0;
37+
3638
#ifdef ZTS
3739
ZEND_API int compiler_globals_id;
3840
ZEND_API int executor_globals_id;
@@ -41,7 +43,6 @@ static HashTable *global_class_table = NULL;
4143
static HashTable *global_constants_table = NULL;
4244
static HashTable *global_auto_globals_table = NULL;
4345
static HashTable *global_persistent_list = NULL;
44-
static zend_uintptr_t global_last_static_member = 0;
4546
ZEND_TSRMLS_CACHE_DEFINE()
4647
# define GLOBAL_FUNCTION_TABLE global_function_table
4748
# define GLOBAL_CLASS_TABLE global_class_table
@@ -631,12 +632,12 @@ static void compiler_globals_ctor(zend_compiler_globals *compiler_globals) /* {{
631632
zend_hash_init_ex(compiler_globals->auto_globals, 8, NULL, auto_global_dtor, 1, 0);
632633
zend_hash_copy(compiler_globals->auto_globals, global_auto_globals_table, auto_global_copy_ctor);
633634

634-
compiler_globals->last_static_member = global_last_static_member;
635-
if (compiler_globals->last_static_member) {
636-
compiler_globals->static_members_table = calloc(compiler_globals->last_static_member + 1, sizeof(zval*));
637-
} else {
638-
compiler_globals->static_members_table = NULL;
639-
}
635+
compiler_globals->request_data_size = global_request_data_size;
636+
//??? if (compiler_globals->request) {
637+
//??? compiler_globals->static_members_table = calloc(compiler_globals->last_static_member + 1, sizeof(zval*));
638+
//??? } else {
639+
compiler_globals->request_data = NULL;
640+
//??? }
640641
compiler_globals->script_encoding_list = NULL;
641642
}
642643
/* }}} */
@@ -655,13 +656,13 @@ static void compiler_globals_dtor(zend_compiler_globals *compiler_globals) /* {{
655656
zend_hash_destroy(compiler_globals->auto_globals);
656657
free(compiler_globals->auto_globals);
657658
}
658-
if (compiler_globals->static_members_table) {
659-
free(compiler_globals->static_members_table);
659+
if (compiler_globals->request_data) {
660+
free(compiler_globals->request_data);
660661
}
661662
if (compiler_globals->script_encoding_list) {
662663
pefree((char*)compiler_globals->script_encoding_list, 1);
663664
}
664-
compiler_globals->last_static_member = 0;
665+
compiler_globals->request_data_size = 0;
665666
}
666667
/* }}} */
667668

@@ -936,7 +937,7 @@ int zend_post_startup(void) /* {{{ */
936937
*GLOBAL_FUNCTION_TABLE = *compiler_globals->function_table;
937938
*GLOBAL_CLASS_TABLE = *compiler_globals->class_table;
938939
*GLOBAL_CONSTANTS_TABLE = *executor_globals->zend_constants;
939-
global_last_static_member = compiler_globals->last_static_member;
940+
global_request_data_size = compiler_globals->request_data_size;
940941

941942
short_tags_default = CG(short_tags);
942943
compiler_options_default = CG(compiler_options);
@@ -955,6 +956,8 @@ int zend_post_startup(void) /* {{{ */
955956
executor_globals_ctor(executor_globals);
956957
global_persistent_list = &EG(persistent_list);
957958
zend_copy_ini_directives();
959+
#else
960+
global_request_data_size = CG(request_data_size);
958961
#endif
959962

960963
if (zend_post_startup_cb) {
@@ -1082,16 +1085,21 @@ ZEND_API void zend_activate(void) /* {{{ */
10821085
init_compiler();
10831086
init_executor();
10841087
startup_scanner();
1088+
1089+
if (CG(request_data_size)) {
1090+
if (!CG(request_data)) {
1091+
CG(request_data) = malloc(sizeof(void*) * CG(request_data_size));
1092+
}
1093+
memset(CG(request_data), 0, sizeof(void*) * CG(request_data_size));
1094+
}
10851095
}
10861096
/* }}} */
10871097

1088-
#ifdef ZTS
1089-
void zend_reset_internal_classes(void) /* {{{ */
1098+
ZEND_API void zend_reset_internal_classes(void) /* {{{ */
10901099
{
1091-
CG(last_static_member) = global_last_static_member;
1100+
CG(request_data_size) = global_request_data_size;
10921101
}
10931102
/* }}} */
1094-
#endif
10951103

10961104
void zend_call_destructors(void) /* {{{ */
10971105
{

Zend/zend.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ ZEND_API void zend_activate_modules(void);
271271
ZEND_API void zend_deactivate_modules(void);
272272
ZEND_API void zend_post_deactivate_modules(void);
273273

274-
void zend_reset_internal_classes(void);
274+
ZEND_API void zend_reset_internal_classes(void);
275275

276276
ZEND_API void free_estring(char **str_p);
277277
END_EXTERN_C()

Zend/zend_API.c

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2795,7 +2795,9 @@ ZEND_API int zend_register_class_alias_ex(const char *name, size_t name_len, zen
27952795
ce = zend_hash_add_ptr(CG(class_table), lcname, ce);
27962796
zend_string_release_ex(lcname, 0);
27972797
if (ce) {
2798-
ce->refcount++;
2798+
if (!(ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
2799+
ce->refcount++;
2800+
}
27992801
return SUCCESS;
28002802
}
28012803
return FAILURE;
@@ -3696,18 +3698,19 @@ ZEND_API int zend_declare_property_ex(zend_class_entry *ce, zend_string *name, z
36963698
ce->default_static_members_table = perealloc(ce->default_static_members_table, sizeof(zval) * ce->default_static_members_count, ce->type == ZEND_INTERNAL_CLASS);
36973699
}
36983700
ZVAL_COPY_VALUE(&ce->default_static_members_table[property_info->offset], property);
3699-
if (ce->type == ZEND_USER_CLASS) {
3701+
if (ce->type == ZEND_USER_CLASS && !(ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
37003702
ce->static_members_table = ce->default_static_members_table;
3701-
#ifdef ZTS
37023703
} else if (!ce->static_members_table_idx) {
3703-
CG(last_static_member)++;
3704-
ce->static_members_table_idx = CG(last_static_member);
3705-
if (CG(static_members_table)) {
3704+
if (!CG(request_data_size)) {
3705+
/* skip 0 */
3706+
CG(request_data_size)++;
3707+
}
3708+
ce->static_members_table_idx = CG(request_data_size)++;
3709+
if (CG(request_data)) {
37063710
/* Support for run-time declaration: dl() */
3707-
CG(static_members_table) = realloc(CG(static_members_table), (CG(last_static_member) + 1) * sizeof(zval*));
3708-
CG(static_members_table)[ce->static_members_table_idx] = NULL;
3711+
CG(request_data) = realloc(CG(request_data), sizeof(zval*) * CG(request_data_size));
3712+
CG(request_data)[ce->static_members_table_idx] = NULL;
37093713
}
3710-
#endif
37113714
}
37123715
} else {
37133716
if ((property_info_ptr = zend_hash_find_ptr(&ce->properties_info, name)) != NULL &&

Zend/zend_API.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -228,11 +228,11 @@ typedef struct _zend_fcall_info_cache {
228228
#define INIT_NS_CLASS_ENTRY(class_container, ns, class_name, functions) \
229229
INIT_CLASS_ENTRY(class_container, ZEND_NS_NAME(ns, class_name), functions)
230230

231-
#ifdef ZTS
232-
# define CE_STATIC_MEMBERS(ce) (((ce)->type==ZEND_USER_CLASS)?(ce)->static_members_table:CG(static_members_table)[(ce)->static_members_table_idx])
233-
#else
234-
# define CE_STATIC_MEMBERS(ce) ((ce)->static_members_table)
235-
#endif
231+
#define CE_STATIC_MEMBERS(ce) \
232+
((zval*)(((ce)->type==ZEND_USER_CLASS && \
233+
!((ce)->ce_flags & ZEND_ACC_IMMUTABLE)) ? \
234+
(ce)->static_members_table : \
235+
CG(request_data)[(ce)->static_members_table_idx]))
236236

237237
#define ZEND_FCI_INITIALIZED(fci) ((fci).size != 0)
238238

Zend/zend_builtin_functions.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1775,7 +1775,7 @@ static int copy_class_or_interface_name(zval *el, int num_args, va_list args, ze
17751775

17761776
if ((hash_key->key && ZSTR_VAL(hash_key->key)[0] != 0)
17771777
&& (comply_mask == (ce->ce_flags & mask))) {
1778-
if (ce->refcount > 1 &&
1778+
if ((ce->refcount > 1 || (ce->ce_flags & ZEND_ACC_IMMUTABLE)) &&
17791779
!same_name(hash_key->key, ce->name)) {
17801780
add_next_index_str(array, zend_string_copy(hash_key->key));
17811781
} else {

Zend/zend_closures.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -658,9 +658,25 @@ ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_ent
658658
closure->func.op_array.static_variables =
659659
zend_array_dup(closure->func.op_array.static_variables);
660660
}
661-
662661
/* Runtime cache is scope-dependent, so we cannot reuse it if the scope changed */
663-
if (!closure->func.op_array.run_time_cache
662+
if (closure->func.common.fn_flags & ZEND_ACC_IMMUTABLE) {
663+
closure->func.common.fn_flags &= ~ZEND_ACC_IMMUTABLE;
664+
closure->func.op_array.run_time_cache = NULL;
665+
if ((func->common.fn_flags & ZEND_ACC_CLOSURE) && func->common.scope == scope) {
666+
/* If a real closure is used for the first time, we create a shared runtime cache
667+
* and remember which scope it is for. */
668+
if (!CG(request_data)[func->op_array.run_time_cache_idx]) {
669+
CG(request_data)[func->op_array.run_time_cache_idx] = zend_arena_alloc(&CG(arena), func->op_array.cache_size);
670+
memset(CG(request_data)[func->op_array.run_time_cache_idx], 0, func->op_array.cache_size);
671+
}
672+
closure->func.op_array.run_time_cache = CG(request_data)[func->op_array.run_time_cache_idx];
673+
} else {
674+
/* Otherwise, we use a non-shared runtime cache */
675+
closure->func.op_array.run_time_cache = emalloc(func->op_array.cache_size);
676+
closure->func.op_array.fn_flags |= ZEND_ACC_HEAP_RT_CACHE;
677+
memset(closure->func.op_array.run_time_cache, 0, func->op_array.cache_size);
678+
}
679+
} else if (!closure->func.op_array.run_time_cache
664680
|| func->common.scope != scope
665681
|| (func->common.fn_flags & ZEND_ACC_HEAP_RT_CACHE)
666682
) {

Zend/zend_compile.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,10 @@ struct _zend_op_array {
390390
uint32_t last; /* number of opcodes */
391391

392392
zend_op *opcodes;
393-
void **run_time_cache;
393+
union {
394+
void **run_time_cache;
395+
zend_uintptr_t run_time_cache_idx;
396+
};
394397
HashTable *static_variables;
395398
zend_string **vars; /* names of CV variables */
396399

@@ -661,19 +664,24 @@ struct _zend_execute_data {
661664
(node).constant = RT_CONSTANT(opline, node) - (op_array)->literals; \
662665
} while (0)
663666

667+
#define RUN_TIME_CACHE(op_array) \
668+
(!((op_array)->fn_flags & ZEND_ACC_IMMUTABLE) ? \
669+
(op_array)->run_time_cache : \
670+
(void**)CG(request_data)[(op_array)->run_time_cache_idx])
671+
664672
#if ZEND_EX_USE_RUN_TIME_CACHE
665673

666674
# define EX_RUN_TIME_CACHE() \
667675
EX(run_time_cache)
668676

669677
# define EX_LOAD_RUN_TIME_CACHE(op_array) do { \
670-
EX(run_time_cache) = (op_array)->run_time_cache; \
678+
EX(run_time_cache) = RUN_TIME_CACHE(op_array); \
671679
} while (0)
672680

673681
#else
674682

675683
# define EX_RUN_TIME_CACHE() \
676-
EX(func)->op_array.run_time_cache
684+
RUN_TIME_CACHE(&EX(func)->op_array)
677685

678686
# define EX_LOAD_RUN_TIME_CACHE(op_array) do { \
679687
} while (0)

Zend/zend_execute.c

Lines changed: 22 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2504,39 +2504,27 @@ static zend_always_inline void i_init_func_execute_data(zend_op_array *op_array,
25042504
}
25052505
/* }}} */
25062506

2507-
static zend_never_inline void ZEND_FASTCALL init_func_run_time_cache(zend_op_array *op_array) /* {{{ */
2508-
{
2509-
ZEND_ASSERT(op_array->run_time_cache == NULL);
2510-
op_array->run_time_cache = zend_arena_alloc(&CG(arena), op_array->cache_size);
2511-
memset(op_array->run_time_cache, 0, op_array->cache_size);
2512-
}
2513-
/* }}} */
2514-
2515-
static zend_always_inline zend_function* ZEND_FASTCALL init_func_run_time_cache_i(zval *zv) /* {{{ */
2507+
static zend_always_inline void init_func_run_time_cache_i(zend_op_array *op_array) /* {{{ */
25162508
{
2517-
zend_op_array *op_array = Z_PTR_P(zv);
2509+
void **run_time_cache;
25182510

2519-
ZEND_ASSERT(op_array->run_time_cache == NULL);
2511+
ZEND_ASSERT(RUN_TIME_CACHE(op_array) == NULL);
2512+
run_time_cache = zend_arena_alloc(&CG(arena), op_array->cache_size);
2513+
memset(run_time_cache, 0, op_array->cache_size);
25202514
if (op_array->fn_flags & ZEND_ACC_IMMUTABLE) {
2521-
zend_op_array *new_op_array = zend_arena_alloc(&CG(arena), sizeof(zend_op_array) + op_array->cache_size);
2522-
2523-
Z_PTR_P(zv) = new_op_array;
2524-
memcpy(new_op_array, op_array, sizeof(zend_op_array));
2525-
new_op_array->fn_flags &= ~ZEND_ACC_IMMUTABLE;
2526-
new_op_array->run_time_cache = (void**)(new_op_array + 1);
2527-
memset(new_op_array->run_time_cache, 0, new_op_array->cache_size);
2528-
return (zend_function*)new_op_array;
2515+
CG(request_data)[op_array->run_time_cache_idx] = run_time_cache;
2516+
if (op_array->static_variables) {
2517+
CG(request_data)[op_array->run_time_cache_idx + 1] = zend_array_dup(op_array->static_variables);
2518+
}
25292519
} else {
2530-
op_array->run_time_cache = zend_arena_alloc(&CG(arena), op_array->cache_size);
2531-
memset(op_array->run_time_cache, 0, op_array->cache_size);
2532-
return (zend_function*)op_array;
2520+
op_array->run_time_cache = run_time_cache;
25332521
}
25342522
}
25352523
/* }}} */
25362524

2537-
static zend_never_inline zend_function* init_func_run_time_cache_ex(zval *zv) /* {{{ */
2525+
static zend_never_inline void ZEND_FASTCALL init_func_run_time_cache(zend_op_array *op_array) /* {{{ */
25382526
{
2539-
return init_func_run_time_cache_i(zv);
2527+
init_func_run_time_cache_i(op_array);
25402528
}
25412529
/* }}} */
25422530

@@ -2547,8 +2535,8 @@ ZEND_API zend_function * ZEND_FASTCALL zend_fetch_function(zend_string *name) /*
25472535
if (EXPECTED(zv != NULL)) {
25482536
zend_function *fbc = Z_FUNC_P(zv);
25492537

2550-
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) {
2551-
fbc = (zend_function*)init_func_run_time_cache_i(zv);
2538+
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
2539+
init_func_run_time_cache_i(&fbc->op_array);
25522540
}
25532541
return fbc;
25542542
}
@@ -2562,8 +2550,8 @@ ZEND_API zend_function * ZEND_FASTCALL zend_fetch_function_str(const char *name,
25622550
if (EXPECTED(zv != NULL)) {
25632551
zend_function *fbc = Z_FUNC_P(zv);
25642552

2565-
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) {
2566-
fbc = (zend_function*)init_func_run_time_cache_i(zv);
2553+
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
2554+
init_func_run_time_cache_i(&fbc->op_array);
25672555
}
25682556
return fbc;
25692557
}
@@ -2602,7 +2590,7 @@ ZEND_API void zend_init_func_execute_data(zend_execute_data *ex, zend_op_array *
26022590
#endif
26032591

26042592
EX(prev_execute_data) = EG(current_execute_data);
2605-
if (!op_array->run_time_cache) {
2593+
if (!RUN_TIME_CACHE(op_array)) {
26062594
init_func_run_time_cache(op_array);
26072595
}
26082596
i_init_func_execute_data(op_array, return_value, 1 EXECUTE_DATA_CC);
@@ -2964,7 +2952,7 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_string(zend_s
29642952
return NULL;
29652953
}
29662954
}
2967-
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) {
2955+
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
29682956
init_func_run_time_cache(&fbc->op_array);
29692957
}
29702958
} else {
@@ -2982,8 +2970,8 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_string(zend_s
29822970
zend_string_release_ex(lcname, 0);
29832971

29842972
fbc = Z_FUNC_P(func);
2985-
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) {
2986-
fbc = init_func_run_time_cache_ex(func);
2973+
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
2974+
init_func_run_time_cache(&fbc->op_array);
29872975
}
29882976
called_scope = NULL;
29892977
}
@@ -3019,7 +3007,7 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_object(zval *
30193007
return NULL;
30203008
}
30213009

3022-
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) {
3010+
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
30233011
init_func_run_time_cache(&fbc->op_array);
30243012
}
30253013

@@ -3106,7 +3094,7 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_array(zend_ar
31063094
return NULL;
31073095
}
31083096

3109-
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) {
3097+
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
31103098
init_func_run_time_cache(&fbc->op_array);
31113099
}
31123100

Zend/zend_execute_API.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -318,9 +318,7 @@ void shutdown_executor(void) /* {{{ */
318318
zend_hash_reverse_apply(EG(zend_constants), clean_non_persistent_constant_full);
319319
zend_hash_reverse_apply(EG(function_table), clean_non_persistent_function_full);
320320
zend_hash_reverse_apply(EG(class_table), clean_non_persistent_class_full);
321-
#ifdef ZTS
322321
zend_reset_internal_classes();
323-
#endif
324322
} else {
325323
ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(EG(zend_constants), key, zv) {
326324
zend_constant *c = Z_PTR_P(zv);

Zend/zend_globals.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,8 @@ struct _zend_compiler_globals {
117117

118118
zend_stack delayed_oplines_stack;
119119

120-
#ifdef ZTS
121-
zval **static_members_table;
122-
zend_uintptr_t last_static_member;
123-
#endif
120+
void **request_data;
121+
zend_uintptr_t request_data_size;
124122
};
125123

126124

0 commit comments

Comments
 (0)
0