diff options
author | Anatol Belski <ab@php.net> | 2017-03-04 10:39:13 +0100 |
---|---|---|
committer | Anatol Belski <ab@php.net> | 2017-03-04 10:39:13 +0100 |
commit | c6982995504b6e21e8a5ade29cfb16a55196dc43 (patch) | |
tree | a196886e83d43fa9ece21e127edde10e3ab57c3e | |
parent | a07272e5b63b404ff7070637137e81634a886bd8 (diff) | |
download | php-git-c6982995504b6e21e8a5ade29cfb16a55196dc43.tar.gz |
Interned strings unification for TS/NTS
Hereby, interned strings are supported in thread safe PHP. The patch
implements two types of interned strings
- interning per process, strings are not freed till process end
- interning per request, strings are freed at request end
There is no runtime interning.
With Opcache, all the permanent iterned strings are copied into SHM on
startup, additional copying into SHM might happen on demand.
-rw-r--r-- | TSRM/TSRM.c | 31 | ||||
-rw-r--r-- | TSRM/TSRM.h | 2 | ||||
-rw-r--r-- | Zend/zend.c | 14 | ||||
-rw-r--r-- | Zend/zend_API.c | 4 | ||||
-rw-r--r-- | Zend/zend_builtin_functions.c | 52 | ||||
-rw-r--r-- | Zend/zend_closures.c | 6 | ||||
-rw-r--r-- | Zend/zend_compile.c | 14 | ||||
-rw-r--r-- | Zend/zend_constants.c | 4 | ||||
-rw-r--r-- | Zend/zend_exceptions.c | 68 | ||||
-rw-r--r-- | Zend/zend_execute.c | 12 | ||||
-rw-r--r-- | Zend/zend_execute_API.c | 2 | ||||
-rw-r--r-- | Zend/zend_globals.h | 5 | ||||
-rw-r--r-- | Zend/zend_ini.c | 2 | ||||
-rw-r--r-- | Zend/zend_language_parser.y | 2 | ||||
-rw-r--r-- | Zend/zend_object_handlers.c | 2 | ||||
-rw-r--r-- | Zend/zend_operators.c | 45 | ||||
-rw-r--r-- | Zend/zend_string.c | 302 | ||||
-rw-r--r-- | Zend/zend_string.h | 56 | ||||
-rw-r--r-- | Zend/zend_vm_def.h | 10 | ||||
-rw-r--r-- | Zend/zend_vm_execute.h | 24 | ||||
-rw-r--r-- | ext/opcache/ZendAccelerator.c | 185 | ||||
-rw-r--r-- | ext/opcache/zend_persist.c | 17 | ||||
-rw-r--r-- | ext/opcache/zend_persist_calc.c | 7 | ||||
-rw-r--r-- | ext/standard/array.c | 18 | ||||
-rw-r--r-- | ext/standard/string.c | 10 | ||||
-rw-r--r-- | main/main.c | 17 | ||||
-rw-r--r-- | main/streams/streams.c | 2 | ||||
-rw-r--r-- | sapi/phpdbg/phpdbg.c | 4 |
28 files changed, 440 insertions, 477 deletions
diff --git a/TSRM/TSRM.c b/TSRM/TSRM.c index 6669df6d43..2c7a40a2de 100644 --- a/TSRM/TSRM.c +++ b/TSRM/TSRM.c @@ -55,8 +55,9 @@ static int resource_types_table_size; static MUTEX_T tsmm_mutex; /* thread-safe memory manager mutex */ /* New thread handlers */ -static tsrm_thread_begin_func_t tsrm_new_thread_begin_handler; -static tsrm_thread_end_func_t tsrm_new_thread_end_handler; +static tsrm_thread_begin_func_t tsrm_new_thread_begin_handler = NULL; +static tsrm_thread_end_func_t tsrm_new_thread_end_handler = NULL; +static tsrm_shutdown_func_t tsrm_shutdown_handler = NULL; /* Debug support */ int tsrm_error(int level, const char *format, ...); @@ -120,6 +121,8 @@ static int32 tls_key; # warning tsrm_set_interpreter_context is probably broken on this platform #endif +TSRM_TLS uint8_t in_main_thread = 0; + /* Startup TSRM (call once for the entire process) */ TSRM_API int tsrm_startup(int expected_threads, int expected_resources, int debug_level, char *debug_filename) { @@ -136,6 +139,9 @@ TSRM_API int tsrm_startup(int expected_threads, int expected_resources, int debu tls_key = tls_allocate(); #endif + /* ensure singleton */ + in_main_thread = 1; + tsrm_error_file = stderr; tsrm_error_set(debug_level, debug_filename); tsrm_tls_table_size = expected_threads; @@ -158,8 +164,6 @@ TSRM_API int tsrm_startup(int expected_threads, int expected_resources, int debu tsmm_mutex = tsrm_mutex_alloc(); - tsrm_new_thread_begin_handler = tsrm_new_thread_end_handler = NULL; - TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Started up TSRM, %d expected threads, %d expected resources", expected_threads, expected_resources)); return 1; } @@ -170,6 +174,11 @@ TSRM_API void tsrm_shutdown(void) { int i; + if (!in_main_thread) { + /* ensure singleton */ + return; + } + if (tsrm_tls_table) { for (i=0; i<tsrm_tls_table_size; i++) { tsrm_tls_entry *p = tsrm_tls_table[i], *next_p; @@ -212,6 +221,12 @@ TSRM_API void tsrm_shutdown(void) #elif defined(TSRM_WIN32) TlsFree(tls_key); #endif + if (tsrm_shutdown_handler) { + tsrm_shutdown_handler(); + } + tsrm_new_thread_begin_handler = NULL; + tsrm_new_thread_end_handler = NULL; + tsrm_shutdown_handler = NULL; } @@ -740,6 +755,14 @@ TSRM_API void *tsrm_set_new_thread_end_handler(tsrm_thread_end_func_t new_thread } +TSRM_API void *tsrm_set_shutdown_handler(tsrm_shutdown_func_t shutdown_handler) +{ + void *retval = (void *) tsrm_shutdown_handler; + + tsrm_shutdown_handler = shutdown_handler; + return retval; +} + /* * Debug support diff --git a/TSRM/TSRM.h b/TSRM/TSRM.h index f9bb241050..2ffcbfee76 100644 --- a/TSRM/TSRM.h +++ b/TSRM/TSRM.h @@ -128,6 +128,7 @@ TSRM_API void ts_free_id(ts_rsrc_id id); typedef void (*tsrm_thread_begin_func_t)(THREAD_T thread_id); typedef void (*tsrm_thread_end_func_t)(THREAD_T thread_id); +typedef void (*tsrm_shutdown_func_t)(void); TSRM_API int tsrm_error(int level, const char *format, ...); @@ -145,6 +146,7 @@ TSRM_API int tsrm_sigmask(int how, const sigset_t *set, sigset_t *oldset); TSRM_API void *tsrm_set_new_thread_begin_handler(tsrm_thread_begin_func_t new_thread_begin_handler); TSRM_API void *tsrm_set_new_thread_end_handler(tsrm_thread_end_func_t new_thread_end_handler); +TSRM_API void *tsrm_set_shutdown_handler(tsrm_shutdown_func_t shutdown_handler); /* these 3 APIs should only be used by people that fully understand the threading model * used by PHP/Zend and the selected SAPI. */ diff --git a/Zend/zend.c b/Zend/zend.c index f6da5735d4..f99a580fa1 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -580,12 +580,6 @@ static void compiler_globals_ctor(zend_compiler_globals *compiler_globals) /* {{ compiler_globals->static_members_table = NULL; } compiler_globals->script_encoding_list = NULL; - - compiler_globals->empty_string = zend_zts_interned_string_init("", sizeof("")-1); - - memset(compiler_globals->one_char_string, 0, sizeof(compiler_globals->one_char_string)); - - zend_known_interned_strings_init(&compiler_globals->known_strings, &compiler_globals->known_strings_count); } /* }}} */ @@ -610,11 +604,6 @@ static void compiler_globals_dtor(zend_compiler_globals *compiler_globals) /* {{ pefree((char*)compiler_globals->script_encoding_list, 1); } compiler_globals->last_static_member = 0; - - zend_zts_interned_string_free(&compiler_globals->empty_string); - - compiler_globals->known_strings = NULL; - compiler_globals->known_strings_count = 0; } /* }}} */ @@ -856,6 +845,7 @@ int zend_startup(zend_utility_functions *utility_functions, char **extensions) / #ifdef ZTS tsrm_set_new_thread_end_handler(zend_new_thread_end_handler); + tsrm_set_shutdown_handler(zend_interned_strings_dtor); #endif return SUCCESS; @@ -967,7 +957,9 @@ void zend_shutdown(void) /* {{{ */ #endif zend_destroy_rsrc_list_dtors(); +#ifndef ZTS zend_interned_strings_dtor(); +#endif } /* }}} */ diff --git a/Zend/zend_API.c b/Zend/zend_API.c index bbea611697..f48c774634 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -2019,6 +2019,7 @@ ZEND_API zend_module_entry* zend_register_module_ex(zend_module_entry *module) / lcname = zend_string_alloc(name_len, 1); zend_str_tolower_copy(ZSTR_VAL(lcname), module->name, name_len); + lcname = zend_new_interned_string(lcname); if ((module_ptr = zend_hash_add_mem(&module_registry, lcname, module, sizeof(zend_module_entry))) == NULL) { zend_error(E_CORE_WARNING, "Module '%s' already loaded", module->name); zend_string_release(lcname); @@ -3816,6 +3817,9 @@ ZEND_API int zend_declare_class_constant(zend_class_entry *ce, const char *name, int ret; zend_string *key = zend_string_init(name, name_length, ce->type & ZEND_INTERNAL_CLASS); + if (ce->type == ZEND_INTERNAL_CLASS) { + key = zend_new_interned_string(key); + } ret = zend_declare_class_constant_ex(ce, key, value, ZEND_ACC_PUBLIC, NULL); zend_string_release(key); return ret; diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 91bf0ee7b0..55d1209ae0 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -763,7 +763,7 @@ ZEND_FUNCTION(each) if (Z_REFCOUNTED_P(entry)) Z_ADDREF_P(entry); } zend_hash_index_add_new(Z_ARRVAL_P(return_value), 1, entry); - zend_hash_add_new(Z_ARRVAL_P(return_value), CG(known_strings)[ZEND_STR_VALUE], entry); + zend_hash_add_new(Z_ARRVAL_P(return_value), ZSTR_KNOWN(ZEND_STR_VALUE), entry); /* add the key elements */ if (zend_hash_get_current_key(target_hash, &key, &num_key) == HASH_KEY_IS_STRING) { @@ -773,7 +773,7 @@ ZEND_FUNCTION(each) ZVAL_LONG(&tmp, num_key); } zend_hash_index_add_new(Z_ARRVAL_P(return_value), 0, &tmp); - zend_hash_add_new(Z_ARRVAL_P(return_value), CG(known_strings)[ZEND_STR_KEY], &tmp); + zend_hash_add_new(Z_ARRVAL_P(return_value), ZSTR_KNOWN(ZEND_STR_KEY), &tmp); zend_hash_move_forward(target_hash); } /* }}} */ @@ -797,7 +797,7 @@ ZEND_FUNCTION(error_reporting) zend_ini_entry *p = EG(error_reporting_ini_entry); if (!p) { - p = zend_hash_find_ptr(EG(ini_directives), CG(known_strings)[ZEND_STR_ERROR_REPORTING]); + p = zend_hash_find_ptr(EG(ini_directives), ZSTR_KNOWN(ZEND_STR_ERROR_REPORTING)); if (p) { EG(error_reporting_ini_entry) = p; } else { @@ -809,7 +809,7 @@ ZEND_FUNCTION(error_reporting) ALLOC_HASHTABLE(EG(modified_ini_directives)); zend_hash_init(EG(modified_ini_directives), 8, NULL, NULL, 0); } - if (EXPECTED(zend_hash_add_ptr(EG(modified_ini_directives), CG(known_strings)[ZEND_STR_ERROR_REPORTING], p) != NULL)) { + if (EXPECTED(zend_hash_add_ptr(EG(modified_ini_directives), ZSTR_KNOWN(ZEND_STR_ERROR_REPORTING), p) != NULL)) { p->orig_value = p->value; p->orig_modifiable = p->modifiable; p->modified = 1; @@ -2659,9 +2659,9 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int lineno = skip->opline->lineno; } ZVAL_STR_COPY(&tmp, filename); - zend_hash_add_new(Z_ARRVAL(stack_frame), CG(known_strings)[ZEND_STR_FILE], &tmp); + zend_hash_add_new(Z_ARRVAL(stack_frame), ZSTR_KNOWN(ZEND_STR_FILE), &tmp); ZVAL_LONG(&tmp, lineno); - zend_hash_add_new(Z_ARRVAL(stack_frame), CG(known_strings)[ZEND_STR_LINE], &tmp); + zend_hash_add_new(Z_ARRVAL(stack_frame), ZSTR_KNOWN(ZEND_STR_LINE), &tmp); /* try to fetch args only if an FCALL was just made - elsewise we're in the middle of a function * and debug_baktrace() might have been called by the error_handler. in this case we don't @@ -2679,9 +2679,9 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int } if (prev->func && ZEND_USER_CODE(prev->func->common.type)) { ZVAL_STR_COPY(&tmp, prev->func->op_array.filename); - zend_hash_add_new(Z_ARRVAL(stack_frame), CG(known_strings)[ZEND_STR_FILE], &tmp); + zend_hash_add_new(Z_ARRVAL(stack_frame), ZSTR_KNOWN(ZEND_STR_FILE), &tmp); ZVAL_LONG(&tmp, prev->opline->lineno); - zend_hash_add_new(Z_ARRVAL(stack_frame), CG(known_strings)[ZEND_STR_LINE], &tmp); + zend_hash_add_new(Z_ARRVAL(stack_frame), ZSTR_KNOWN(ZEND_STR_LINE), &tmp); break; } prev_call = prev; @@ -2707,7 +2707,7 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int if (function_name) { ZVAL_STR_COPY(&tmp, function_name); - zend_hash_add_new(Z_ARRVAL(stack_frame), CG(known_strings)[ZEND_STR_FUNCTION], &tmp); + zend_hash_add_new(Z_ARRVAL(stack_frame), ZSTR_KNOWN(ZEND_STR_FUNCTION), &tmp); if (object) { if (func->common.scope) { @@ -2717,27 +2717,27 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int } else { ZVAL_STR(&tmp, object->handlers->get_class_name(object)); } - zend_hash_add_new(Z_ARRVAL(stack_frame), CG(known_strings)[ZEND_STR_CLASS], &tmp); + zend_hash_add_new(Z_ARRVAL(stack_frame), ZSTR_KNOWN(ZEND_STR_CLASS), &tmp); if ((options & DEBUG_BACKTRACE_PROVIDE_OBJECT) != 0) { ZVAL_OBJ(&tmp, object); - zend_hash_add_new(Z_ARRVAL(stack_frame), CG(known_strings)[ZEND_STR_OBJECT], &tmp); + zend_hash_add_new(Z_ARRVAL(stack_frame), ZSTR_KNOWN(ZEND_STR_OBJECT), &tmp); Z_ADDREF(tmp); } - ZVAL_INTERNED_STR(&tmp, CG(known_strings)[ZEND_STR_OBJECT_OPERATOR]); - zend_hash_add_new(Z_ARRVAL(stack_frame), CG(known_strings)[ZEND_STR_TYPE], &tmp); + ZVAL_INTERNED_STR(&tmp, ZSTR_KNOWN(ZEND_STR_OBJECT_OPERATOR)); + zend_hash_add_new(Z_ARRVAL(stack_frame), ZSTR_KNOWN(ZEND_STR_TYPE), &tmp); } else if (func->common.scope) { ZVAL_STR_COPY(&tmp, func->common.scope->name); - zend_hash_add_new(Z_ARRVAL(stack_frame), CG(known_strings)[ZEND_STR_CLASS], &tmp); - ZVAL_INTERNED_STR(&tmp, CG(known_strings)[ZEND_STR_PAAMAYIM_NEKUDOTAYIM]); - zend_hash_add_new(Z_ARRVAL(stack_frame), CG(known_strings)[ZEND_STR_TYPE], &tmp); + zend_hash_add_new(Z_ARRVAL(stack_frame), ZSTR_KNOWN(ZEND_STR_CLASS), &tmp); + ZVAL_INTERNED_STR(&tmp, ZSTR_KNOWN(ZEND_STR_PAAMAYIM_NEKUDOTAYIM)); + zend_hash_add_new(Z_ARRVAL(stack_frame), ZSTR_KNOWN(ZEND_STR_TYPE), &tmp); } if ((options & DEBUG_BACKTRACE_IGNORE_ARGS) == 0 && func->type != ZEND_EVAL_CODE) { debug_backtrace_get_args(call, &tmp); - zend_hash_add_new(Z_ARRVAL(stack_frame), CG(known_strings)[ZEND_STR_ARGS], &tmp); + zend_hash_add_new(Z_ARRVAL(stack_frame), ZSTR_KNOWN(ZEND_STR_ARGS), &tmp); } } else { /* i know this is kinda ugly, but i'm trying to avoid extra cycles in the main execution loop */ @@ -2746,30 +2746,30 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int if (!ptr->func || !ZEND_USER_CODE(ptr->func->common.type) || ptr->opline->opcode != ZEND_INCLUDE_OR_EVAL) { /* can happen when calling eval from a custom sapi */ - pseudo_function_name = CG(known_strings)[ZEND_STR_UNKNOWN]; + pseudo_function_name = ZSTR_KNOWN(ZEND_STR_UNKNOWN); build_filename_arg = 0; } else switch (ptr->opline->extended_value) { case ZEND_EVAL: - pseudo_function_name = CG(known_strings)[ZEND_STR_EVAL]; + pseudo_function_name = ZSTR_KNOWN(ZEND_STR_EVAL); build_filename_arg = 0; break; case ZEND_INCLUDE: - pseudo_function_name = CG(known_strings)[ZEND_STR_INCLUDE]; + pseudo_function_name = ZSTR_KNOWN(ZEND_STR_INCLUDE); break; case ZEND_REQUIRE: - pseudo_function_name = CG(known_strings)[ZEND_STR_REQUIRE]; + pseudo_function_name = ZSTR_KNOWN(ZEND_STR_REQUIRE); break; case ZEND_INCLUDE_ONCE: - pseudo_function_name = CG(known_strings)[ZEND_STR_INCLUDE_ONCE]; + pseudo_function_name = ZSTR_KNOWN(ZEND_STR_INCLUDE_ONCE); break; case ZEND_REQUIRE_ONCE: - pseudo_function_name = CG(known_strings)[ZEND_STR_REQUIRE_ONCE]; + pseudo_function_name = ZSTR_KNOWN(ZEND_STR_REQUIRE_ONCE); break; default: /* this can actually happen if you use debug_backtrace() in your error_handler and * you're in the top-scope */ - pseudo_function_name = CG(known_strings)[ZEND_STR_UNKNOWN]; + pseudo_function_name = ZSTR_KNOWN(ZEND_STR_UNKNOWN); build_filename_arg = 0; break; } @@ -2785,11 +2785,11 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int ZVAL_STR_COPY(&tmp, include_filename); zend_hash_next_index_insert_new(Z_ARRVAL(arg_array), &tmp); - zend_hash_add_new(Z_ARRVAL(stack_frame), CG(known_strings)[ZEND_STR_ARGS], &arg_array); + zend_hash_add_new(Z_ARRVAL(stack_frame), ZSTR_KNOWN(ZEND_STR_ARGS), &arg_array); } ZVAL_INTERNED_STR(&tmp, pseudo_function_name); - zend_hash_add_new(Z_ARRVAL(stack_frame), CG(known_strings)[ZEND_STR_FUNCTION], &tmp); + zend_hash_add_new(Z_ARRVAL(stack_frame), ZSTR_KNOWN(ZEND_STR_FUNCTION), &tmp); } zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &stack_frame); diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index 8b37d10994..6e7b30361f 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -369,7 +369,7 @@ ZEND_API zend_function *zend_get_closure_invoke_method(zend_object *object) /* { invoke->internal_function.handler = ZEND_MN(Closure___invoke); invoke->internal_function.module = 0; invoke->internal_function.scope = zend_ce_closure; - invoke->internal_function.function_name = CG(known_strings)[ZEND_STR_MAGIC_INVOKE]; + invoke->internal_function.function_name = ZSTR_KNOWN(ZEND_STR_MAGIC_INVOKE); return invoke; } /* }}} */ @@ -509,12 +509,12 @@ static HashTable *zend_closure_get_debug_info(zval *object, int *is_temp) /* {{{ if (closure->func.type == ZEND_USER_FUNCTION && closure->func.op_array.static_variables) { HashTable *static_variables = closure->func.op_array.static_variables; ZVAL_ARR(&val, zend_array_dup(static_variables)); - zend_hash_update(debug_info, CG(known_strings)[ZEND_STR_STATIC], &val); + zend_hash_update(debug_info, ZSTR_KNOWN(ZEND_STR_STATIC), &val); } if (Z_TYPE(closure->this_ptr) != IS_UNDEF) { Z_ADDREF(closure->this_ptr); - zend_hash_update(debug_info, CG(known_strings)[ZEND_STR_THIS], &closure->this_ptr); + zend_hash_update(debug_info, ZSTR_KNOWN(ZEND_STR_THIS), &closure->this_ptr); } if (arg_info && diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 2fc6fb08ec..88d71925a8 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -3467,13 +3467,7 @@ int zend_compile_func_chr(znode *result, zend_ast_list *args) /* {{{ */ zend_long c = Z_LVAL_P(zend_ast_get_zval(args->child[0])) & 0xff; result->op_type = IS_CONST; - if (CG(one_char_string)[c]) { - ZVAL_INTERNED_STR(&result->u.constant, CG(one_char_string)[c]); - } else { - ZVAL_NEW_STR(&result->u.constant, zend_string_alloc(1, 0)); - Z_STRVAL_P(&result->u.constant)[0] = (char)c; - Z_STRVAL_P(&result->u.constant)[1] = '\0'; - } + ZVAL_INTERNED_STR(&result->u.constant, ZSTR_CHAR(c)); return SUCCESS; } else { return FAILURE; @@ -8216,11 +8210,7 @@ void zend_eval_const_expr(zend_ast **ast_ptr) /* {{{ */ return; } c = (zend_uchar) Z_STRVAL_P(container)[offset]; - if (CG(one_char_string)[c]) { - ZVAL_INTERNED_STR(&result, CG(one_char_string)[c]); - } else { - ZVAL_NEW_STR(&result, zend_string_init((char *) &c, 1, 0)); - } + ZVAL_INTERNED_STR(&result, ZSTR_CHAR(c)); } else if (Z_TYPE_P(container) <= IS_FALSE) { ZVAL_NULL(&result); } else { diff --git a/Zend/zend_constants.c b/Zend/zend_constants.c index 17f80aa19a..14dd08dad0 100644 --- a/Zend/zend_constants.c +++ b/Zend/zend_constants.c @@ -489,6 +489,10 @@ ZEND_API int zend_register_constant(zend_constant *c) printf("Registering constant for module %d\n", c->module_number); #endif + if (c->module_number != PHP_USER_CONSTANT) { + c->name = zend_new_interned_string(c->name); + } + if (!(c->flags & CONST_CS)) { lowercase_name = zend_string_alloc(ZSTR_LEN(c->name), c->flags & CONST_PERSISTENT); zend_str_tolower_copy(ZSTR_VAL(lowercase_name), ZSTR_VAL(c->name), ZSTR_LEN(c->name)); diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index d9db617855..9895b09556 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -88,18 +88,18 @@ void zend_exception_set_previous(zend_object *exception, zend_object *add_previo ZVAL_OBJ(&zv, exception); ex = &zv; do { - ancestor = zend_read_property_ex(i_get_exception_base(&pv), &pv, CG(known_strings)[ZEND_STR_PREVIOUS], 1, &rv); + ancestor = zend_read_property_ex(i_get_exception_base(&pv), &pv, ZSTR_KNOWN(ZEND_STR_PREVIOUS), 1, &rv); while (Z_TYPE_P(ancestor) == IS_OBJECT) { if (Z_OBJ_P(ancestor) == Z_OBJ_P(ex)) { OBJ_RELEASE(add_previous); return; } - ancestor = zend_read_property_ex(i_get_exception_base(ancestor), ancestor, CG(known_strings)[ZEND_STR_PREVIOUS], 1, &rv); + ancestor = zend_read_property_ex(i_get_exception_base(ancestor), ancestor, ZSTR_KNOWN(ZEND_STR_PREVIOUS), 1, &rv); } base_ce = i_get_exception_base(ex); - previous = zend_read_property_ex(base_ce, ex, CG(known_strings)[ZEND_STR_PREVIOUS], 1, &rv); + previous = zend_read_property_ex(base_ce, ex, ZSTR_KNOWN(ZEND_STR_PREVIOUS), 1, &rv); if (Z_TYPE_P(previous) == IS_NULL) { - zend_update_property_ex(base_ce, ex, CG(known_strings)[ZEND_STR_PREVIOUS], &pv); + zend_update_property_ex(base_ce, ex, ZSTR_KNOWN(ZEND_STR_PREVIOUS), &pv); GC_REFCOUNT(add_previous)--; return; } @@ -223,17 +223,17 @@ static zend_object *zend_default_exception_new_ex(zend_class_entry *class_type, if (EXPECTED(class_type != zend_ce_parse_error || !(filename = zend_get_compiled_filename()))) { ZVAL_STRING(&tmp, zend_get_executed_filename()); - zend_update_property_ex(base_ce, &obj, CG(known_strings)[ZEND_STR_FILE], &tmp); + zend_update_property_ex(base_ce, &obj, ZSTR_KNOWN(ZEND_STR_FILE), &tmp); zval_ptr_dtor(&tmp); ZVAL_LONG(&tmp, zend_get_executed_lineno()); - zend_update_property_ex(base_ce, &obj, CG(known_strings)[ZEND_STR_LINE], &tmp); + zend_update_property_ex(base_ce, &obj, ZSTR_KNOWN(ZEND_STR_LINE), &tmp); } else { ZVAL_STR(&tmp, filename); - zend_update_property_ex(base_ce, &obj, CG(known_strings)[ZEND_STR_FILE], &tmp); + zend_update_property_ex(base_ce, &obj, ZSTR_KNOWN(ZEND_STR_FILE), &tmp); ZVAL_LONG(&tmp, zend_get_compiled_lineno()); - zend_update_property_ex(base_ce, &obj, CG(known_strings)[ZEND_STR_LINE], &tmp); + zend_update_property_ex(base_ce, &obj, ZSTR_KNOWN(ZEND_STR_LINE), &tmp); } - zend_update_property_ex(base_ce, &obj, CG(known_strings)[ZEND_STR_TRACE], &trace); + zend_update_property_ex(base_ce, &obj, ZSTR_KNOWN(ZEND_STR_TRACE), &trace); return object; } @@ -289,16 +289,16 @@ ZEND_METHOD(exception, __construct) if (message) { ZVAL_STR(&tmp, message); - zend_update_property_ex(base_ce, object, CG(known_strings)[ZEND_STR_MESSAGE], &tmp); + zend_update_property_ex(base_ce, object, ZSTR_KNOWN(ZEND_STR_MESSAGE), &tmp); } if (code) { ZVAL_LONG(&tmp, code); - zend_update_property_ex(base_ce, object, CG(known_strings)[ZEND_STR_CODE], &tmp); + zend_update_property_ex(base_ce, object, ZSTR_KNOWN(ZEND_STR_CODE), &tmp); } if (previous) { - zend_update_property_ex(base_ce, object, CG(known_strings)[ZEND_STR_PREVIOUS], previous); + zend_update_property_ex(base_ce, object, ZSTR_KNOWN(ZEND_STR_PREVIOUS), previous); } } /* }}} */ @@ -306,9 +306,9 @@ ZEND_METHOD(exception, __construct) /* {{{ proto Exception::__wakeup() Exception unserialize checks */ #define CHECK_EXC_TYPE(id, type) \ - pvalue = zend_read_property_ex(i_get_exception_base(object), (object), CG(known_strings)[id], 1, &value); \ + pvalue = zend_read_property_ex(i_get_exception_base(object), (object), ZSTR_KNOWN(id), 1, &value); \ if (Z_TYPE_P(pvalue) != IS_NULL && Z_TYPE_P(pvalue) != type) { \ - zend_unset_property(i_get_exception_base(object), object, ZSTR_VAL(CG(known_strings)[id]), ZSTR_LEN(CG(known_strings)[id])); \ + zend_unset_property(i_get_exception_base(object), object, ZSTR_VAL(ZSTR_KNOWN(id)), ZSTR_LEN(ZSTR_KNOWN(id))); \ } ZEND_METHOD(exception, __wakeup) @@ -358,31 +358,31 @@ ZEND_METHOD(error_exception, __construct) if (message) { ZVAL_STRING(&tmp, message); - zend_update_property_ex(zend_ce_exception, object, CG(known_strings)[ZEND_STR_MESSAGE], &tmp); + zend_update_property_ex(zend_ce_exception, object, ZSTR_KNOWN(ZEND_STR_MESSAGE), &tmp); zval_ptr_dtor(&tmp); } if (code) { ZVAL_LONG(&tmp, code); - zend_update_property_ex(zend_ce_exception, object, CG(known_strings)[ZEND_STR_CODE], &tmp); + zend_update_property_ex(zend_ce_exception, object, ZSTR_KNOWN(ZEND_STR_CODE), &tmp); } if (previous) { - zend_update_property_ex(zend_ce_exception, object, CG(known_strings)[ZEND_STR_PREVIOUS], previous); + zend_update_property_ex(zend_ce_exception, object, ZSTR_KNOWN(ZEND_STR_PREVIOUS), previous); } ZVAL_LONG(&tmp, severity); - zend_update_property_ex(zend_ce_exception, object, CG(known_strings)[ZEND_STR_SEVERITY], &tmp); + zend_update_property_ex(zend_ce_exception, object, ZSTR_KNOWN(ZEND_STR_SEVERITY), &tmp); if (argc >= 4) { ZVAL_STRING(&tmp, filename); - zend_update_property_ex(zend_ce_exception, object, CG(known_strings)[ZEND_STR_FILE], &tmp); + zend_update_property_ex(zend_ce_exception, object, ZSTR_KNOWN(ZEND_STR_FILE), &tmp); zval_ptr_dtor(&tmp); if (argc < 5) { lineno = 0; /* invalidate lineno */ } ZVAL_LONG(&tmp, lineno); - zend_update_property_ex(zend_ce_exception, object, CG(known_strings)[ZEND_STR_LINE], &tmp); + zend_update_property_ex(zend_ce_exception, object, ZSTR_KNOWN(ZEND_STR_LINE), &tmp); } } /* }}} */ @@ -393,9 +393,9 @@ ZEND_METHOD(error_exception, __construct) } #define GET_PROPERTY(object, id) \ - zend_read_property_ex(i_get_exception_base(object), (object), CG(known_strings)[id], 0, &rv) + zend_read_property_ex(i_get_exception_base(object), (object), ZSTR_KNOWN(id), 0, &rv) #define GET_PROPERTY_SILENT(object, id) \ - zend_read_property_ex(i_get_exception_base(object), (object), CG(known_strings)[id], 1, &rv) + zend_read_property_ex(i_get_exception_base(object), (object), ZSTR_KNOWN(id), 1, &rv) /* {{{ proto string Exception|Error::getFile() Get the file in which the exception occurred */ @@ -547,14 +547,14 @@ static void _build_trace_string(smart_str *str, HashTable *ht, uint32_t num) /* smart_str_append_long(str, num); smart_str_appendc(str, ' '); - file = zend_hash_find(ht, CG(known_strings)[ZEND_STR_FILE]); + file = zend_hash_find(ht, ZSTR_KNOWN(ZEND_STR_FILE)); if (file) { if (Z_TYPE_P(file) != IS_STRING) { zend_error(E_WARNING, "Function name is no string"); smart_str_appends(str, "[unknown function]"); } else{ zend_long line; - tmp = zend_hash_find(ht, CG(known_strings)[ZEND_STR_LINE]); + tmp = zend_hash_find(ht, ZSTR_KNOWN(ZEND_STR_LINE)); if (tmp) { if (Z_TYPE_P(tmp) == IS_LONG) { line = Z_LVAL_P(tmp); @@ -573,11 +573,11 @@ static void _build_trace_string(smart_str *str, HashTable *ht, uint32_t num) /* } else { smart_str_appends(str, "[internal function]: "); } - TRACE_APPEND_KEY(CG(known_strings)[ZEND_STR_CLASS]); - TRACE_APPEND_KEY(CG(known_strings)[ZEND_STR_TYPE]); - TRACE_APPEND_KEY(CG(known_strings)[ZEND_STR_FUNCTION]); + TRACE_APPEND_KEY(ZSTR_KNOWN(ZEND_STR_CLASS)); + TRACE_APPEND_KEY(ZSTR_KNOWN(ZEND_STR_TYPE)); + TRACE_APPEND_KEY(ZSTR_KNOWN(ZEND_STR_FUNCTION)); smart_str_appendc(str, '('); - tmp = zend_hash_find(ht, CG(known_strings)[ZEND_STR_ARGS]); + tmp = zend_hash_find(ht, ZSTR_KNOWN(ZEND_STR_ARGS)); if (tmp) { if (Z_TYPE_P(tmp) == IS_ARRAY) { size_t last_len = ZSTR_LEN(str->s); @@ -614,7 +614,7 @@ ZEND_METHOD(exception, getTraceAsString) object = getThis(); base_ce = i_get_exception_base(object); - trace = zend_read_property_ex(base_ce, object, CG(known_strings)[ZEND_STR_TRACE], 1, &rv); + trace = zend_read_property_ex(base_ce, object, ZSTR_KNOWN(ZEND_STR_TRACE), 1, &rv); if (Z_TYPE_P(trace) != IS_ARRAY) { RETURN_FALSE; } @@ -736,7 +736,7 @@ ZEND_METHOD(exception, __toString) /* We store the result in the private property string so we can access * the result in uncaught exception handlers without memleaks. */ ZVAL_STR(&tmp, str); - zend_update_property_ex(base_ce, exception, CG(known_strings)[ZEND_STR_STRING], &tmp); + zend_update_property_ex(base_ce, exception, ZSTR_KNOWN(ZEND_STR_STRING), &tmp); RETURN_STR(str); } @@ -896,12 +896,12 @@ ZEND_API ZEND_COLD zend_object *zend_throw_exception(zend_class_entry *exception if (message) { ZVAL_STRING(&tmp, message); - zend_update_property_ex(exception_ce, &ex, CG(known_strings)[ZEND_STR_MESSAGE], &tmp); + zend_update_property_ex(exception_ce, &ex, ZSTR_KNOWN(ZEND_STR_MESSAGE), &tmp); zval_ptr_dtor(&tmp); } if (code) { ZVAL_LONG(&tmp, code); - zend_update_property_ex(exception_ce, &ex, CG(known_strings)[ZEND_STR_CODE], &tmp); + zend_update_property_ex(exception_ce, &ex, ZSTR_KNOWN(ZEND_STR_CODE), &tmp); } zend_throw_exception_internal(&ex); @@ -930,7 +930,7 @@ ZEND_API ZEND_COLD zend_object *zend_throw_error_exception(zend_class_entry *exc zend_object *obj = zend_throw_exception(exception_ce, message, code); ZVAL_OBJ(&ex, obj); ZVAL_LONG(&tmp, severity); - zend_update_property_ex(zend_ce_error_exception, &ex, CG(known_strings)[ZEND_STR_SEVERITY], &tmp); + zend_update_property_ex(zend_ce_error_exception, &ex, ZSTR_KNOWN(ZEND_STR_SEVERITY), &tmp); return obj; } /* }}} */ @@ -983,7 +983,7 @@ ZEND_API ZEND_COLD void zend_exception_error(zend_object *ex, int severity) /* { if (Z_TYPE(tmp) != IS_STRING) { zend_error(E_WARNING, "%s::__toString() must return a string", ZSTR_VAL(ce_exception->name)); } else { - zend_update_property_ex(i_get_exception_base(&exception), &exception, CG(known_strings)[ZEND_STR_STRING], &tmp); + zend_update_property_ex(i_get_exception_base(&exception), &exception, ZSTR_KNOWN(ZEND_STR_STRING), &tmp); } } zval_ptr_dtor(&tmp); diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 68f5b3ce6c..451185969c 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1264,11 +1264,7 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim, if (result) { /* Return the new character */ - if (CG(one_char_string)[c]) { - ZVAL_INTERNED_STR(result, CG(one_char_string)[c]); - } else { - ZVAL_NEW_STR(result, zend_string_init(Z_STRVAL_P(str) + offset, 1, 0)); - } + ZVAL_INTERNED_STR(result, ZSTR_CHAR(c)); } } @@ -1781,11 +1777,7 @@ try_string_offset: ? (zend_long)Z_STRLEN_P(container) + offset : offset; c = (zend_uchar)Z_STRVAL_P(container)[real_offset]; - if (CG(one_char_string)[c]) { - ZVAL_INTERNED_STR(result, CG(one_char_string)[c]); - } else { - ZVAL_NEW_STR(result, zend_string_init(Z_STRVAL_P(container) + real_offset, 1, 0)); - } + ZVAL_INTERNED_STR(result, ZSTR_CHAR(c)); } } else if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { if (/*dim_type == IS_CV &&*/ UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) { diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 7747fa4e58..07eb7a8ef3 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -975,7 +975,7 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, const zval *k } if (!EG(autoload_func)) { - zend_function *func = zend_hash_find_ptr(EG(function_table), CG(known_strings)[ZEND_STR_MAGIC_AUTOLOAD]); + zend_function *func = zend_hash_find_ptr(EG(function_table), ZSTR_KNOWN(ZEND_STR_MAGIC_AUTOLOAD)); if (func) { EG(autoload_func) = func; } else { diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index 3440edfc69..151f47c71f 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -110,11 +110,6 @@ struct _zend_compiler_globals { zend_arena *arena; - zend_string *empty_string; - zend_string *one_char_string[256]; - zend_string **known_strings; - uint32_t known_strings_count; - HashTable interned_strings; const zend_encoding **script_encoding_list; diff --git a/Zend/zend_ini.c b/Zend/zend_ini.c index 4dd1bbe7c9..e6070dfb91 100644 --- a/Zend/zend_ini.c +++ b/Zend/zend_ini.c @@ -359,7 +359,7 @@ ZEND_API int zend_alter_ini_entry_ex(zend_string *name, zend_string *new_value, ini_entry->orig_value = ini_entry->value; ini_entry->orig_modifiable = modifiable; ini_entry->modified = 1; - zend_hash_add_ptr(EG(modified_ini_directives), name, ini_entry); + zend_hash_add_ptr(EG(modified_ini_directives), ini_entry->name, ini_entry); } duplicate = zend_string_copy(new_value); diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 92524c69e0..9970ce3a07 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -1030,7 +1030,7 @@ function_call: class_name: T_STATIC - { zval zv; ZVAL_INTERNED_STR(&zv, CG(known_strings)[ZEND_STR_STATIC]); + { zval zv; ZVAL_INTERNED_STR(&zv, ZSTR_KNOWN(ZEND_STR_STATIC)); $$ = zend_ast_create_zval_ex(&zv, ZEND_NAME_NOT_FQ); } | name { $$ = $1; } ; diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 4ec90ba096..66de460a30 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -1682,7 +1682,7 @@ int zend_std_get_closure(zval *obj, zend_class_entry **ce_ptr, zend_function **f ce = Z_OBJCE_P(obj); - if ((func = zend_hash_find(&ce->function_table, CG(known_strings)[ZEND_STR_MAGIC_INVOKE])) == NULL) { + if ((func = zend_hash_find(&ce->function_table, ZSTR_KNOWN(ZEND_STR_MAGIC_INVOKE))) == NULL) { return FAILURE; } *fptr_ptr = Z_FUNC_P(func); diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index 37fa5e9825..41d1ca62e1 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -525,11 +525,7 @@ try_again: break; } case IS_TRUE: - if (CG(one_char_string)['1']) { - ZVAL_INTERNED_STR(op, CG(one_char_string)['1']); - } else { - ZVAL_NEW_STR(op, zend_string_init("1", 1, 0)); - } + ZVAL_INTERNED_STR(op, ZSTR_CHAR('1')); break; case IS_STRING: break; @@ -677,7 +673,7 @@ try_again: zval tmp; ZVAL_COPY_VALUE(&tmp, op); object_init(op); - zend_hash_add_new(Z_OBJPROP_P(op), CG(known_strings)[ZEND_STR_SCALAR], &tmp); + zend_hash_add_new(Z_OBJPROP_P(op), ZSTR_KNOWN(ZEND_STR_SCALAR), &tmp); break; } } @@ -850,11 +846,7 @@ try_again: case IS_FALSE: return ZSTR_EMPTY_ALLOC(); case IS_TRUE: - if (CG(one_char_string)['1']) { - return CG(one_char_string)['1']; - } else { - return zend_string_init("1", 1, 0); - } + return ZSTR_CHAR('1'); case IS_RESOURCE: { char buf[sizeof("Resource id #") + MAX_LENGTH_OF_LONG]; int len; @@ -1364,11 +1356,7 @@ try_again: if (Z_STRLEN_P(op1) == 1) { zend_uchar not = (zend_uchar) ~*Z_STRVAL_P(op1); - if (CG(one_char_string)[not]) { - ZVAL_INTERNED_STR(result, CG(one_char_string)[not]); - } else { - ZVAL_NEW_STR(result, zend_string_init((char *) ¬, 1, 0)); - } + ZVAL_INTERNED_STR(result, ZSTR_CHAR(not)); } else { ZVAL_NEW_STR(result, zend_string_alloc(Z_STRLEN_P(op1), 0)); for (i = 0; i < Z_STRLEN_P(op1); i++) { @@ -1416,11 +1404,7 @@ ZEND_API int ZEND_FASTCALL bitwise_or_function(zval *result, zval *op1, zval *op if (result==op1) { zend_string_release(Z_STR_P(result)); } - if (CG(one_char_string)[or]) { - ZVAL_INTERNED_STR(result, CG(one_char_string)[or]); - } else { - ZVAL_NEW_STR(result, zend_string_init((char *) &or, 1, 0)); - } + ZVAL_INTERNED_STR(result, ZSTR_CHAR(or)); return SUCCESS; } longer = op1; @@ -1498,11 +1482,7 @@ ZEND_API int ZEND_FASTCALL bitwise_and_function(zval *result, zval *op1, zval *o if (result==op1) { zend_string_release(Z_STR_P(result)); } - if (CG(one_char_string)[and]) { - ZVAL_INTERNED_STR(result, CG(one_char_string)[and]); - } else { - ZVAL_NEW_STR(result, zend_string_init((char *) &and, 1, 0)); - } + ZVAL_INTERNED_STR(result, ZSTR_CHAR(and)); return SUCCESS; } longer = op1; @@ -1580,11 +1560,7 @@ ZEND_API int ZEND_FASTCALL bitwise_xor_function(zval *result, zval *op1, zval *o if (result==op1) { zend_string_release(Z_STR_P(result)); } - if (CG(one_char_string)[xor]) { - ZVAL_INTERNED_STR(result, CG(one_char_string)[xor]); - } else { - ZVAL_NEW_STR(result, zend_string_init((char *) &xor, 1, 0)); - } + ZVAL_INTERNED_STR(result, ZSTR_CHAR(xor)); return SUCCESS; } longer = op1; @@ -2297,12 +2273,7 @@ static void ZEND_FASTCALL increment_string(zval *str) /* {{{ */ if (Z_STRLEN_P(str) == 0) { zend_string_release(Z_STR_P(str)); - if (CG(one_char_string)['1']) { - ZVAL_INTERNED_STR(str, CG(one_char_string)['1']); - } else { - Z_STR_P(str) = zend_string_init("1", sizeof("1")-1, 0); - Z_TYPE_INFO_P(str) = IS_STRING_EX; - } + ZVAL_INTERNED_STR(str, ZSTR_CHAR('1')); return; } diff --git a/Zend/zend_string.c b/Zend/zend_string.c index dbc44870c2..d3fbdf2f19 100644 --- a/Zend/zend_string.c +++ b/Zend/zend_string.c @@ -22,48 +22,33 @@ #include "zend_globals.h" ZEND_API zend_string *(*zend_new_interned_string)(zend_string *str); -ZEND_API void (*zend_interned_strings_snapshot)(void); -ZEND_API void (*zend_interned_strings_restore)(void); -static zend_string *zend_new_interned_string_int(zend_string *str); -static void zend_interned_strings_snapshot_int(void); -static void zend_interned_strings_restore_int(void); +static zend_string *zend_new_interned_string_permanent(zend_string *str); +static zend_string *zend_new_interned_string_request(zend_string *str); + +/* Any strings interned in the startup phase. Common to all the threads, + won't be free'd until process exit. If we want an ability to + add permanent strings even after startup, it would be still + possible on costs of locking in the thread safe builds. */ +static HashTable interned_strings_permanent; + +static zend_new_interned_string_func_t interned_string_request_handler = zend_new_interned_string_request; +static zend_string_copy_storage_func_t interned_string_copy_storage = NULL; + +ZEND_API zend_string *zend_empty_string = NULL; +ZEND_API zend_string *zend_one_char_string[256]; +ZEND_API zend_string **zend_known_strings = NULL; ZEND_API zend_ulong zend_hash_func(const char *str, size_t len) { return zend_inline_hash_func(str, len); } -#ifndef ZTS static void _str_dtor(zval *zv) { zend_string *str = Z_STR_P(zv); pefree(str, GC_FLAGS(str) & IS_STR_PERSISTENT); } -#endif - -/* Readonly, so assigned also per thread. */ -static const zend_string **known_interned_strings = NULL; -static uint32_t known_interned_strings_count = 0; - -ZEND_API uint32_t zend_intern_known_strings(const char **strings, uint32_t count) -{ - uint32_t i, old_count = known_interned_strings_count; - - known_interned_strings = perealloc(known_interned_strings, sizeof(char*) * (old_count + count), 1); - for (i = 0; i < count; i++) { -#ifndef ZTS - zend_string *str = zend_string_init(strings[i], strlen(strings[i]), 1); - known_interned_strings[known_interned_strings_count + i] = - zend_new_interned_string_int(str); -#else - known_interned_strings[known_interned_strings_count + i] = - zend_zts_interned_string_init(strings[i], strlen(strings[i])); -#endif - } - known_interned_strings_count = old_count + count; - return old_count; -} static const char *known_strings[] = { #define _ZEND_STR_DSC(id, str) str, @@ -72,175 +57,202 @@ ZEND_KNOWN_STRINGS(_ZEND_STR_DSC) NULL }; -void zend_known_interned_strings_init(zend_string ***strings, uint32_t *count) +static void zend_init_interned_strings_ht(HashTable *interned_strings, int permanent) { - *strings = (zend_string **)known_interned_strings; - *count = known_interned_strings_count; + zend_hash_init(interned_strings, 1024, NULL, _str_dtor, permanent); + + interned_strings->nTableMask = -interned_strings->nTableSize; + HT_SET_DATA_ADDR(interned_strings, pemalloc(HT_SIZE(interned_strings), permanent)); + HT_HASH_RESET(interned_strings); + interned_strings->u.flags |= HASH_FLAG_INITIALIZED; } -void zend_interned_strings_init(void) +ZEND_API void zend_interned_strings_init(void) { -#ifndef ZTS + char s[2]; + int i; zend_string *str; - zend_hash_init(&CG(interned_strings), 1024, NULL, _str_dtor, 1); + zend_init_interned_strings_ht(&interned_strings_permanent, 1); - CG(interned_strings).nTableMask = -CG(interned_strings).nTableSize; - HT_SET_DATA_ADDR(&CG(interned_strings), pemalloc(HT_SIZE(&CG(interned_strings)), 1)); - HT_HASH_RESET(&CG(interned_strings)); - CG(interned_strings).u.flags |= HASH_FLAG_INITIALIZED; + zend_new_interned_string = zend_new_interned_string_permanent; /* interned empty string */ str = zend_string_alloc(sizeof("")-1, 1); ZSTR_VAL(str)[0] = '\000'; - CG(empty_string) = zend_new_interned_string_int(str); -#endif + zend_empty_string = zend_new_interned_string_permanent(str); - /* one char strings (the actual interned strings are going to be created by ext/opcache) */ - memset(CG(one_char_string), 0, sizeof(CG(one_char_string))); + s[1] = 0; + for (i = 0; i < 256; i++) { + s[0] = i; + zend_one_char_string[i] = zend_new_interned_string_permanent(zend_string_init(s, 1, 1)); + } /* known strings */ - zend_intern_known_strings(known_strings, (sizeof(known_strings) / sizeof(known_strings[0])) - 1); - zend_known_interned_strings_init(&CG(known_strings), &CG(known_strings_count)); - - zend_new_interned_string = zend_new_interned_string_int; - zend_interned_strings_snapshot = zend_interned_strings_snapshot_int; - zend_interned_strings_restore = zend_interned_strings_restore_int; + zend_known_strings = pemalloc(sizeof(zend_string*) * ((sizeof(known_strings) / sizeof(known_strings[0]) - 1)), 1); + for (i = 0; i < (sizeof(known_strings) / sizeof(known_strings[0])) - 1; i++) { + str = zend_string_init(known_strings[i], strlen(known_strings[i]), 1); + zend_known_strings[i] = zend_new_interned_string_permanent(str); + } } -void zend_interned_strings_dtor(void) +ZEND_API void zend_interned_strings_dtor(void) { -#ifndef ZTS - zend_hash_destroy(&CG(interned_strings)); -#else - uint32_t i; + zend_hash_destroy(&interned_strings_permanent); - for (i = 0; i < CG(known_strings_count); i++) { - zend_zts_interned_string_free(&CG(known_strings)[i]); - } -#endif - free(CG(known_strings)); - CG(known_strings) = NULL; - CG(known_strings_count) = 0; - known_interned_strings = NULL; - known_interned_strings_count = 0; + free(zend_known_strings); + zend_known_strings = NULL; } -static zend_string *zend_new_interned_string_int(zend_string *str) +static zend_always_inline zend_string *zend_interned_string_ht_lookup(zend_string *str, HashTable *interned_strings) { -#ifndef ZTS zend_ulong h; uint32_t nIndex; uint32_t idx; Bucket *p; - if (ZSTR_IS_INTERNED(str)) { - return str; - } - h = zend_string_hash_val(str); - nIndex = h | CG(interned_strings).nTableMask; - idx = HT_HASH(&CG(interned_strings), nIndex); + nIndex = h | interned_strings->nTableMask; + idx = HT_HASH(interned_strings, nIndex); while (idx != HT_INVALID_IDX) { - p = HT_HASH_TO_BUCKET(&CG(interned_strings), idx); + p = HT_HASH_TO_BUCKET(interned_strings, idx); if ((p->h == h) && (ZSTR_LEN(p->key) == ZSTR_LEN(str))) { if (!memcmp(ZSTR_VAL(p->key), ZSTR_VAL(str), ZSTR_LEN(str))) { - zend_string_release(str); return p->key; } } idx = Z_NEXT(p->val); } + return NULL; +} + +static zend_never_inline void zend_string_table_grow(HashTable *interned_strings) +{ + if (EXPECTED(interned_strings->nTableSize < HT_MAX_SIZE)) { /* Let's double the table size */ + void *new_data; + void *old_data = HT_GET_DATA_ADDR(interned_strings); + Bucket *old_buckets = interned_strings->arData; + + interned_strings->nTableSize += interned_strings->nTableSize; + interned_strings->nTableMask = -interned_strings->nTableSize; + new_data = pemalloc(HT_SIZE(interned_strings), interned_strings->u.flags & HASH_FLAG_PERSISTENT); + + HT_SET_DATA_ADDR(interned_strings, new_data); + memcpy(interned_strings->arData, old_buckets, sizeof(Bucket) * interned_strings->nNumUsed); + pefree(old_data, interned_strings->u.flags & HASH_FLAG_PERSISTENT); + zend_hash_rehash(interned_strings); + } +} + +/* This function might be not thread safe at least because it would update the + hash val in the passed string. Be sure it is called in the appropriate context. */ +static zend_always_inline zend_string *zend_add_interned_string(zend_string *str, HashTable *interned_strings, uint32_t flags) +{ + zend_ulong h; + uint32_t nIndex; + uint32_t idx; + Bucket *p; + + h = zend_string_hash_val(str); + GC_REFCOUNT(str) = 1; - GC_FLAGS(str) |= IS_STR_INTERNED; - - if (CG(interned_strings).nNumUsed >= CG(interned_strings).nTableSize) { - if (CG(interned_strings).nTableSize < HT_MAX_SIZE) { /* Let's double the table size */ - void *new_data; - void *old_data = HT_GET_DATA_ADDR(&CG(interned_strings)); - Bucket *old_buckets = CG(interned_strings).arData; - - CG(interned_strings).nTableSize += CG(interned_strings).nTableSize; - CG(interned_strings).nTableMask = -CG(interned_strings).nTableSize; - new_data = malloc(HT_SIZE(&CG(interned_strings))); - - if (new_data) { - HT_SET_DATA_ADDR(&CG(interned_strings), new_data); - memcpy(CG(interned_strings).arData, old_buckets, sizeof(Bucket) * CG(interned_strings).nNumUsed); - free(old_data); - zend_hash_rehash(&CG(interned_strings)); - } else { - CG(interned_strings).nTableSize = CG(interned_strings).nTableSize >> 1; - CG(interned_strings).nTableMask = -CG(interned_strings).nTableSize; - } - } + GC_FLAGS(str) |= IS_STR_INTERNED | flags; + + if (UNEXPECTED(interned_strings->nNumUsed >= interned_strings->nTableSize)) { + zend_string_table_grow(interned_strings); } - idx = CG(interned_strings).nNumUsed++; - CG(interned_strings).nNumOfElements++; - p = CG(interned_strings).arData + idx; + idx = interned_strings->nNumUsed++; + interned_strings->nNumOfElements++; + p = interned_strings->arData + idx; p->h = h; p->key = str; Z_STR(p->val) = str; Z_TYPE_INFO(p->val) = IS_INTERNED_STRING_EX; - nIndex = h | CG(interned_strings).nTableMask; - Z_NEXT(p->val) = HT_HASH(&CG(interned_strings), nIndex); - HT_HASH(&CG(interned_strings), nIndex) = HT_IDX_TO_HASH(idx); + nIndex = h | interned_strings->nTableMask; + Z_NEXT(p->val) = HT_HASH(interned_strings, nIndex); + HT_HASH(interned_strings, nIndex) = HT_IDX_TO_HASH(idx); return str; -#else - return str; -#endif } -static void zend_interned_strings_snapshot_int(void) +ZEND_API zend_string *zend_interned_string_find_permanent(zend_string *str) { -#ifndef ZTS - uint32_t idx; - Bucket *p; + return zend_interned_string_ht_lookup(str, &interned_strings_permanent); +} + + +static zend_string *zend_new_interned_string_permanent(zend_string *str) +{ + zend_string *ret; + + if (ZSTR_IS_INTERNED(str)) { + return str; + } - idx = CG(interned_strings).nNumUsed; - while (idx > 0) { - idx--; - p = CG(interned_strings).arData + idx; - ZEND_ASSERT(GC_FLAGS(p->key) & IS_STR_PERSISTENT); - GC_FLAGS(p->key) |= IS_STR_PERMANENT; + ret = zend_interned_string_ht_lookup(str, &interned_strings_permanent); + if (ret) { + zend_string_release(str); + return ret; } -#endif + + return zend_add_interned_string(str, &interned_strings_permanent, IS_STR_PERMANENT); } -static void zend_interned_strings_restore_int(void) +static zend_string *zend_new_interned_string_request(zend_string *str) { -#ifndef ZTS - uint32_t nIndex; - uint32_t idx; - Bucket *p; + zend_string *ret; + + if (ZSTR_IS_INTERNED(str)) { + return str; + } + + /* Check for permanent strings, the table is readonly at this point. */ + ret = zend_interned_string_ht_lookup(str, &interned_strings_permanent); + if (ret) { + zend_string_release(str); + return ret; + } + + ret = zend_interned_string_ht_lookup(str, &CG(interned_strings)); + if (ret) { + zend_string_release(str); + return ret; + } + + /* Create a short living interned, freed after the request. */ + ret = zend_add_interned_string(str, &CG(interned_strings), 0); + + return ret; +} + +ZEND_API void zend_interned_strings_activate(void) +{ + zend_init_interned_strings_ht(&CG(interned_strings), 0); +} - idx = CG(interned_strings).nNumUsed; - while (idx > 0) { - idx--; - p = CG(interned_strings).arData + idx; - if (GC_FLAGS(p->key) & IS_STR_PERMANENT) break; - CG(interned_strings).nNumUsed--; - CG(interned_strings).nNumOfElements--; - - GC_FLAGS(p->key) &= ~IS_STR_INTERNED; - GC_REFCOUNT(p->key) = 1; - zend_string_free(p->key); - - nIndex = p->h | CG(interned_strings).nTableMask; - if (HT_HASH(&CG(interned_strings), nIndex) == HT_IDX_TO_HASH(idx)) { - HT_HASH(&CG(interned_strings), nIndex) = Z_NEXT(p->val); - } else { - uint32_t prev = HT_HASH(&CG(interned_strings), nIndex); - while (Z_NEXT(HT_HASH_TO_BUCKET(&CG(interned_strings), prev)->val) != idx) { - prev = Z_NEXT(HT_HASH_TO_BUCKET(&CG(interned_strings), prev)->val); - } - Z_NEXT(HT_HASH_TO_BUCKET(&CG(interned_strings), prev)->val) = Z_NEXT(p->val); - } - } -#endif +ZEND_API void zend_interned_strings_deactivate(void) +{ + zend_hash_destroy(&CG(interned_strings)); +} + +ZEND_API void zend_interned_strings_set_request_storage_handler(zend_new_interned_string_func_t handler) +{ + interned_string_request_handler = handler; +} + +ZEND_API void zend_interned_strings_set_permanent_storage_copy_handler(zend_string_copy_storage_func_t handler) +{ + interned_string_copy_storage = handler; +} + +ZEND_API void zend_interned_strings_switch_storage(void) +{ + if (interned_string_copy_storage) { + interned_string_copy_storage(); + } + zend_new_interned_string = interned_string_request_handler; } /* diff --git a/Zend/zend_string.h b/Zend/zend_string.h index 025082e9c9..77dd083997 100644 --- a/Zend/zend_string.h +++ b/Zend/zend_string.h @@ -25,14 +25,24 @@ BEGIN_EXTERN_C() -ZEND_API extern zend_string *(*zend_new_interned_string)(zend_string *str); -ZEND_API extern void (*zend_interned_strings_snapshot)(void); -ZEND_API extern void (*zend_interned_strings_restore)(void); +typedef void (*zend_string_copy_storage_func_t)(void); +typedef zend_string *(*zend_new_interned_string_func_t)(zend_string *str); + +ZEND_API extern zend_new_interned_string_func_t zend_new_interned_string; ZEND_API zend_ulong zend_hash_func(const char *str, size_t len); -void zend_interned_strings_init(void); -void zend_interned_strings_dtor(void); -void zend_known_interned_strings_init(zend_string ***, uint32_t *); +ZEND_API void zend_interned_strings_init(void); +ZEND_API void zend_interned_strings_dtor(void); +ZEND_API void zend_interned_strings_activate(void); +ZEND_API void zend_interned_strings_deactivate(void); +ZEND_API zend_string *zend_interned_string_find_permanent(zend_string *str); +ZEND_API void zend_interned_strings_set_request_storage_handler(zend_new_interned_string_func_t handler); +ZEND_API void zend_interned_strings_set_permanent_storage_copy_handler(zend_string_copy_storage_func_t handler); +ZEND_API void zend_interned_strings_switch_storage(void); + +ZEND_API extern zend_string *zend_empty_string; +ZEND_API extern zend_string *zend_one_char_string[256]; +ZEND_API extern zend_string **zend_known_strings; END_EXTERN_C() @@ -56,7 +66,9 @@ END_EXTERN_C() #define ZSTR_IS_INTERNED(s) (GC_FLAGS(s) & IS_STR_INTERNED) -#define ZSTR_EMPTY_ALLOC() CG(empty_string) +#define ZSTR_EMPTY_ALLOC() zend_empty_string +#define ZSTR_CHAR(c) zend_one_char_string[c] +#define ZSTR_KNOWN(idx) zend_known_strings[idx] #define _ZSTR_HEADER_SIZE XtOffsetOf(zend_string, val) @@ -162,6 +174,13 @@ static zend_always_inline zend_string *zend_string_init(const char *str, size_t return ret; } +static zend_always_inline zend_string *zend_string_init_interned(const char *str, size_t len, int persistent) +{ + zend_string *ret = zend_string_init(str, len, persistent); + + return zend_new_interned_string(ret); +} + static zend_always_inline zend_string *zend_string_copy(zend_string *s) { if (!ZSTR_IS_INTERNED(s)) { @@ -359,27 +378,6 @@ EMPTY_SWITCH_DEFAULT_CASE() #endif } -#ifdef ZTS -static zend_always_inline zend_string* zend_zts_interned_string_init(const char *val, size_t len) -{ - zend_string *str; - - str = zend_string_init(val, len, 1); - - zend_string_hash_val(str); - GC_FLAGS(str) |= IS_STR_INTERNED; - return str; -} - -static zend_always_inline void zend_zts_interned_string_free(zend_string **s) -{ - if (NULL != *s) { - free(*s); - *s = NULL; - } -} -#endif - #define ZEND_KNOWN_STRINGS(_) \ _(ZEND_STR_FILE, "file") \ _(ZEND_STR_LINE, "line") \ @@ -419,8 +417,6 @@ ZEND_KNOWN_STRINGS(_ZEND_STR_ID) ZEND_STR_LAST_KNOWN } zend_known_string_id; -ZEND_API uint32_t zend_intern_known_strings(const char **strings, uint32_t count); - #endif /* ZEND_STRING_H */ /* diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index cbc5804c99..2cf46f699e 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1397,7 +1397,7 @@ ZEND_VM_HELPER(zend_fetch_var_address_helper, CONST|TMPVAR|CV, UNUSED, int type) target_symbol_table = zend_get_target_symbol_table(execute_data, opline->extended_value & ZEND_FETCH_TYPE_MASK); retval = zend_hash_find(target_symbol_table, name); if (retval == NULL) { - if (UNEXPECTED(zend_string_equals(name, CG(known_strings)[ZEND_STR_THIS]))) { + if (UNEXPECTED(zend_string_equals(name, ZSTR_KNOWN(ZEND_STR_THIS)))) { zval *result; ZEND_VM_C_LABEL(fetch_this): @@ -1457,7 +1457,7 @@ ZEND_VM_C_LABEL(fetch_this): } else if (Z_TYPE_P(retval) == IS_INDIRECT) { retval = Z_INDIRECT_P(retval); if (Z_TYPE_P(retval) == IS_UNDEF) { - if (UNEXPECTED(zend_string_equals(name, CG(known_strings)[ZEND_STR_THIS]))) { + if (UNEXPECTED(zend_string_equals(name, ZSTR_KNOWN(ZEND_STR_THIS)))) { ZEND_VM_C_GOTO(fetch_this); } switch (type) { @@ -5207,7 +5207,7 @@ ZEND_VM_HANDLER(21, ZEND_CAST, CONST|TMP|VAR|CV, ANY, TYPE) if (Z_TYPE_P(expr) != IS_ARRAY) { object_init(result); if (Z_TYPE_P(expr) != IS_NULL) { - expr = zend_hash_add_new(Z_OBJPROP_P(result), CG(known_strings)[ZEND_STR_SCALAR], expr); + expr = zend_hash_add_new(Z_OBJPROP_P(result), ZSTR_KNOWN(ZEND_STR_SCALAR), expr); if (OP1_TYPE == IS_CONST) { if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr); } else { @@ -6569,7 +6569,7 @@ ZEND_VM_HANDLER(57, ZEND_BEGIN_SILENCE, ANY, ANY) do { EG(error_reporting) = 0; if (!EG(error_reporting_ini_entry)) { - zend_ini_entry *p = zend_hash_find_ptr(EG(ini_directives), CG(known_strings)[ZEND_STR_ERROR_REPORTING]); + zend_ini_entry *p = zend_hash_find_ptr(EG(ini_directives), ZSTR_KNOWN(ZEND_STR_ERROR_REPORTING)); if (p) { EG(error_reporting_ini_entry) = p; } else { @@ -6581,7 +6581,7 @@ ZEND_VM_HANDLER(57, ZEND_BEGIN_SILENCE, ANY, ANY) ALLOC_HASHTABLE(EG(modified_ini_directives)); zend_hash_init(EG(modified_ini_directives), 8, NULL, NULL, 0); } - if (EXPECTED(zend_hash_add_ptr(EG(modified_ini_directives), CG(known_strings)[ZEND_STR_ERROR_REPORTING], EG(error_reporting_ini_entry)) != NULL)) { + if (EXPECTED(zend_hash_add_ptr(EG(modified_ini_directives), ZSTR_KNOWN(ZEND_STR_ERROR_REPORTING), EG(error_reporting_ini_entry)) != NULL)) { EG(error_reporting_ini_entry)->orig_value = EG(error_reporting_ini_entry)->value; EG(error_reporting_ini_entry)->orig_modifiable = EG(error_reporting_ini_entry)->modifiable; EG(error_reporting_ini_entry)->modified = 1; diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index fac8f6e475..3bdbaa936b 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1508,7 +1508,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BEGIN_SILENCE_SPEC_HANDLER(ZEN do { EG(error_reporting) = 0; if (!EG(error_reporting_ini_entry)) { - zend_ini_entry *p = zend_hash_find_ptr(EG(ini_directives), CG(known_strings)[ZEND_STR_ERROR_REPORTING]); + zend_ini_entry *p = zend_hash_find_ptr(EG(ini_directives), ZSTR_KNOWN(ZEND_STR_ERROR_REPORTING)); if (p) { EG(error_reporting_ini_entry) = p; } else { @@ -1520,7 +1520,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BEGIN_SILENCE_SPEC_HANDLER(ZEN ALLOC_HASHTABLE(EG(modified_ini_directives)); zend_hash_init(EG(modified_ini_directives), 8, NULL, NULL, 0); } - if (EXPECTED(zend_hash_add_ptr(EG(modified_ini_directives), CG(known_strings)[ZEND_STR_ERROR_REPORTING], EG(error_reporting_ini_entry)) != NULL)) { + if (EXPECTED(zend_hash_add_ptr(EG(modified_ini_directives), ZSTR_KNOWN(ZEND_STR_ERROR_REPORTING), EG(error_reporting_ini_entry)) != NULL)) { EG(error_reporting_ini_entry)->orig_value = EG(error_reporting_ini_entry)->value; EG(error_reporting_ini_entry)->orig_modifiable = EG(error_reporting_ini_entry)->modifiable; EG(error_reporting_ini_entry)->modified = 1; @@ -3404,7 +3404,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_CONST_HANDLER(ZEND_O if (Z_TYPE_P(expr) != IS_ARRAY) { object_init(result); if (Z_TYPE_P(expr) != IS_NULL) { - expr = zend_hash_add_new(Z_OBJPROP_P(result), CG(known_strings)[ZEND_STR_SCALAR], expr); + expr = zend_hash_add_new(Z_OBJPROP_P(result), ZSTR_KNOWN(ZEND_STR_SCALAR), expr); if (IS_CONST == IS_CONST) { if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr); } else { @@ -7029,7 +7029,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_ target_symbol_table = zend_get_target_symbol_table(execute_data, opline->extended_value & ZEND_FETCH_TYPE_MASK); retval = zend_hash_find(target_symbol_table, name); if (retval == NULL) { - if (UNEXPECTED(zend_string_equals(name, CG(known_strings)[ZEND_STR_THIS]))) { + if (UNEXPECTED(zend_string_equals(name, ZSTR_KNOWN(ZEND_STR_THIS)))) { zval *result; fetch_this: @@ -7089,7 +7089,7 @@ fetch_this: } else if (Z_TYPE_P(retval) == IS_INDIRECT) { retval = Z_INDIRECT_P(retval); if (Z_TYPE_P(retval) == IS_UNDEF) { - if (UNEXPECTED(zend_string_equals(name, CG(known_strings)[ZEND_STR_THIS]))) { + if (UNEXPECTED(zend_string_equals(name, ZSTR_KNOWN(ZEND_STR_THIS)))) { goto fetch_this; } switch (type) { @@ -12639,7 +12639,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_TMP_HANDLER(ZEND_OPC if (Z_TYPE_P(expr) != IS_ARRAY) { object_init(result); if (Z_TYPE_P(expr) != IS_NULL) { - expr = zend_hash_add_new(Z_OBJPROP_P(result), CG(known_strings)[ZEND_STR_SCALAR], expr); + expr = zend_hash_add_new(Z_OBJPROP_P(result), ZSTR_KNOWN(ZEND_STR_SCALAR), expr); if (IS_TMP_VAR == IS_CONST) { if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr); } else { @@ -16248,7 +16248,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_VAR_HANDLER(ZEND_OPC if (Z_TYPE_P(expr) != IS_ARRAY) { object_init(result); if (Z_TYPE_P(expr) != IS_NULL) { - expr = zend_hash_add_new(Z_OBJPROP_P(result), CG(known_strings)[ZEND_STR_SCALAR], expr); + expr = zend_hash_add_new(Z_OBJPROP_P(result), ZSTR_KNOWN(ZEND_STR_SCALAR), expr); if (IS_VAR == IS_CONST) { if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr); } else { @@ -33514,7 +33514,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_CV_HANDLER(ZEND_OPCO if (Z_TYPE_P(expr) != IS_ARRAY) { object_init(result); if (Z_TYPE_P(expr) != IS_NULL) { - expr = zend_hash_add_new(Z_OBJPROP_P(result), CG(known_strings)[ZEND_STR_SCALAR], expr); + expr = zend_hash_add_new(Z_OBJPROP_P(result), ZSTR_KNOWN(ZEND_STR_SCALAR), expr); if (IS_CV == IS_CONST) { if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr); } else { @@ -39301,7 +39301,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_ target_symbol_table = zend_get_target_symbol_table(execute_data, opline->extended_value & ZEND_FETCH_TYPE_MASK); retval = zend_hash_find(target_symbol_table, name); if (retval == NULL) { - if (UNEXPECTED(zend_string_equals(name, CG(known_strings)[ZEND_STR_THIS]))) { + if (UNEXPECTED(zend_string_equals(name, ZSTR_KNOWN(ZEND_STR_THIS)))) { zval *result; fetch_this: @@ -39361,7 +39361,7 @@ fetch_this: } else if (Z_TYPE_P(retval) == IS_INDIRECT) { retval = Z_INDIRECT_P(retval); if (Z_TYPE_P(retval) == IS_UNDEF) { - if (UNEXPECTED(zend_string_equals(name, CG(known_strings)[ZEND_STR_THIS]))) { + if (UNEXPECTED(zend_string_equals(name, ZSTR_KNOWN(ZEND_STR_THIS)))) { goto fetch_this; } switch (type) { @@ -50071,7 +50071,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_ target_symbol_table = zend_get_target_symbol_table(execute_data, opline->extended_value & ZEND_FETCH_TYPE_MASK); retval = zend_hash_find(target_symbol_table, name); if (retval == NULL) { - if (UNEXPECTED(zend_string_equals(name, CG(known_strings)[ZEND_STR_THIS]))) { + if (UNEXPECTED(zend_string_equals(name, ZSTR_KNOWN(ZEND_STR_THIS)))) { zval *result; fetch_this: @@ -50131,7 +50131,7 @@ fetch_this: } else if (Z_TYPE_P(retval) == IS_INDIRECT) { retval = Z_INDIRECT_P(retval); if (Z_TYPE_P(retval) == IS_UNDEF) { - if (UNEXPECTED(zend_string_equals(name, CG(known_strings)[ZEND_STR_THIS]))) { + if (UNEXPECTED(zend_string_equals(name, ZSTR_KNOWN(ZEND_STR_THIS)))) { goto fetch_this; } switch (type) { diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index ff347a96e3..28b5d958f3 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -341,9 +341,6 @@ static inline void accel_unlock_all(void) } /* Interned strings support */ -static zend_string *(*orig_new_interned_string)(zend_string *str); -static void (*orig_interned_strings_snapshot)(void); -static void (*orig_interned_strings_restore)(void); /* O+ disables creation of interned strings by regular PHP compiler, instead, * it creates interned strings in shared memory when saves a script. @@ -354,15 +351,6 @@ static zend_string *accel_new_interned_string_for_php(zend_string *str) return str; } -static void accel_interned_strings_snapshot_for_php(void) -{ -} - -static void accel_interned_strings_restore_for_php(void) -{ -} - -#ifndef ZTS static void accel_interned_strings_restore_state(void) { uint32_t idx = ZCSG(interned_strings).nNumUsed; @@ -396,9 +384,7 @@ static void accel_interned_strings_save_state(void) { ZCSG(interned_strings_saved_top) = ZCSG(interned_strings_top); } -#endif -#ifndef ZTS static zend_string *accel_find_interned_string(zend_string *str) { /* for now interned strings are supported only for non-ZTS build */ @@ -411,6 +397,7 @@ static zend_string *accel_find_interned_string(zend_string *str) /* this is already an interned string */ return str; } + if (!ZCG(counted)) { if (accel_activate_add() == FAILURE) { return str; @@ -436,12 +423,9 @@ static zend_string *accel_find_interned_string(zend_string *str) return NULL; } -#endif zend_string *accel_new_interned_string(zend_string *str) { -/* for now interned strings are supported only for non-ZTS build */ -#ifndef ZTS zend_ulong h; uint32_t nIndex; uint32_t idx; @@ -505,28 +489,24 @@ zend_string *accel_new_interned_string(zend_string *str) HT_HASH(&ZCSG(interned_strings), nIndex) = HT_IDX_TO_HASH(idx); zend_string_release(str); return p->key; -#else - return str; -#endif } -#ifndef ZTS /* Copy PHP interned strings from PHP process memory into the shared memory */ -static void accel_use_shm_interned_strings(void) +static void accel_copy_permanent_strings(zend_new_interned_string_func_t new_interned_string) { uint32_t idx, j; Bucket *p, *q; /* empty string */ - CG(empty_string) = accel_new_interned_string(CG(empty_string)); + zend_empty_string = new_interned_string(zend_empty_string); for (j = 0; j < 256; j++) { char s[2]; s[0] = j; s[1] = 0; - CG(one_char_string)[j] = accel_new_interned_string(zend_string_init(s, 1, 0)); + zend_one_char_string[j] = new_interned_string(zend_string_init(s, 1, 0)); } - for (j = 0; j < CG(known_strings_count); j++) { - CG(known_strings)[j] = accel_new_interned_string(CG(known_strings)[j]); + for (j = 0; j < ZEND_STR_LAST_KNOWN; j++) { + zend_known_strings[j] = new_interned_string(zend_known_strings[j]); } /* function table hash keys */ @@ -534,10 +514,10 @@ static void accel_use_shm_interned_strings(void) p = CG(function_table)->arData + idx; if (Z_TYPE(p->val) == IS_UNDEF) continue; if (p->key) { - p->key = accel_new_interned_string(p->key); + p->key = new_interned_string(p->key); } if (Z_FUNC(p->val)->common.function_name) { - Z_FUNC(p->val)->common.function_name = accel_new_interned_string(Z_FUNC(p->val)->common.function_name); + Z_FUNC(p->val)->common.function_name = new_interned_string(Z_FUNC(p->val)->common.function_name); } if (Z_FUNC(p->val)->common.arg_info && (Z_FUNC(p->val)->common.fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS))) { @@ -551,7 +531,7 @@ static void accel_use_shm_interned_strings(void) for (i = 0 ; i < num_args; i++) { if (ZEND_TYPE_IS_CLASS(arg_info[i].type)) { zend_bool allow_null = ZEND_TYPE_ALLOW_NULL(arg_info[i].type); - arg_info[i].type = ZEND_TYPE_ENCODE_CLASS(accel_new_interned_string(ZEND_TYPE_NAME(arg_info[i].type)), allow_null); + arg_info[i].type = ZEND_TYPE_ENCODE_CLASS(new_interned_string(ZEND_TYPE_NAME(arg_info[i].type)), allow_null); } } } @@ -566,11 +546,11 @@ static void accel_use_shm_interned_strings(void) ce = (zend_class_entry*)Z_PTR(p->val); if (p->key) { - p->key = accel_new_interned_string(p->key); + p->key = new_interned_string(p->key); } if (ce->name) { - ce->name = accel_new_interned_string(ce->name); + ce->name = new_interned_string(ce->name); } for (j = 0; j < ce->properties_info.nNumUsed; j++) { @@ -582,11 +562,11 @@ static void accel_use_shm_interned_strings(void) info = (zend_property_info*)Z_PTR(q->val); if (q->key) { - q->key = accel_new_interned_string(q->key); + q->key = new_interned_string(q->key); } if (info->name) { - info->name = accel_new_interned_string(info->name); + info->name = new_interned_string(info->name); } } @@ -594,10 +574,10 @@ static void accel_use_shm_interned_strings(void) q = ce->function_table.arData + j; if (Z_TYPE(q->val) == IS_UNDEF) continue; if (q->key) { - q->key = accel_new_interned_string(q->key); + q->key = new_interned_string(q->key); } if (Z_FUNC(q->val)->common.function_name) { - Z_FUNC(q->val)->common.function_name = accel_new_interned_string(Z_FUNC(q->val)->common.function_name); + Z_FUNC(q->val)->common.function_name = new_interned_string(Z_FUNC(q->val)->common.function_name); } } @@ -605,17 +585,23 @@ static void accel_use_shm_interned_strings(void) q = ce->constants_table.arData + j; if (Z_TYPE(q->val) == IS_UNDEF) continue; if (q->key) { - q->key = accel_new_interned_string(q->key); + q->key = new_interned_string(q->key); } } } /* constant hash keys */ for (idx = 0; idx < EG(zend_constants)->nNumUsed; idx++) { + zend_constant *c; + p = EG(zend_constants)->arData + idx; if (Z_TYPE(p->val) == IS_UNDEF) continue; if (p->key) { - p->key = accel_new_interned_string(p->key); + p->key = new_interned_string(p->key); + } + c = (zend_constant*)Z_PTR(p->val); + if (c->name) { + c->name = new_interned_string(c->name); } } @@ -629,13 +615,70 @@ static void accel_use_shm_interned_strings(void) auto_global = (zend_auto_global*)Z_PTR(p->val);; zend_string_addref(auto_global->name); - auto_global->name = accel_new_interned_string(auto_global->name); + auto_global->name = new_interned_string(auto_global->name); + if (p->key) { + p->key = new_interned_string(p->key); + } + } + + for (idx = 0; idx < module_registry.nNumUsed; idx++) { + p = module_registry.arData + idx; + if (p->key) { - p->key = accel_new_interned_string(p->key); + p->key = new_interned_string(p->key); } } } -#endif + +static zend_string *accel_replace_string_by_shm_permanent(zend_string *str) +{ + zend_string *ret = accel_find_interned_string(str); + + if (ret) { + zend_string_release(str); + return ret; + } + return str; +} + +static zend_string *accel_replace_string_by_process_permanent(zend_string *str) +{ + zend_string *ret = zend_interned_string_find_permanent(str); + + if (ret) { + zend_string_release(str); + return ret; + } + ZEND_ASSERT(0); + return str; +} + + +static void accel_use_shm_interned_strings(void) +{ + HANDLE_BLOCK_INTERRUPTIONS(); + SHM_UNPROTECT(); + zend_shared_alloc_lock(); + + if (ZCSG(interned_strings_saved_top) == NULL) { + accel_copy_permanent_strings(accel_new_interned_string); + } else { + accel_copy_permanent_strings(accel_replace_string_by_shm_permanent); + if (ZCG(counted)) { + accel_deactivate_sub(); + } + } + accel_interned_strings_save_state(); + + zend_shared_alloc_unlock(); + SHM_PROTECT(); + HANDLE_UNBLOCK_INTERRUPTIONS(); +} + +static void accel_use_permanent_interned_strings(void) +{ + accel_copy_permanent_strings(accel_replace_string_by_process_permanent); +} #ifndef ZEND_WIN32 static inline void kill_all_lockers(struct flock *mem_usage_check) @@ -1015,7 +1058,6 @@ char *accel_make_persistent_key(const char *path, int path_length, int *key_len) } cwd = ZSTR_VAL(cwd_str); cwd_len = ZSTR_LEN(cwd_str); -#ifndef ZTS if (ZCG(cwd_check)) { ZCG(cwd_check) = 0; if ((ZCG(counted) || ZCSG(accelerator_enabled))) { @@ -1044,7 +1086,6 @@ char *accel_make_persistent_key(const char *path, int path_length, int *key_len) } } } -#endif } if (EXPECTED(ZCG(include_path_key_len))) { @@ -1057,7 +1098,6 @@ char *accel_make_persistent_key(const char *path, int path_length, int *key_len) include_path = ZSTR_VAL(ZCG(include_path)); include_path_len = ZSTR_LEN(ZCG(include_path)); -#ifndef ZTS if (ZCG(include_path_check)) { ZCG(include_path_check) = 0; if ((ZCG(counted) || ZCSG(accelerator_enabled))) { @@ -1085,7 +1125,6 @@ char *accel_make_persistent_key(const char *path, int path_length, int *key_len) } } } -#endif } /* Calculate key length */ @@ -2174,11 +2213,9 @@ static void accel_activate(void) zend_reset_cache_vars(); zend_accel_hash_clean(&ZCSG(hash)); -#if !defined(ZTS) if (ZCG(accel_directives).interned_strings_buffer) { accel_interned_strings_restore_state(); } -#endif zend_shared_alloc_restore_state(); ZCSG(accelerator_enabled) = ZCSG(cache_status_before_restart); @@ -2514,7 +2551,6 @@ static int zend_accel_init_shm(void) zend_accel_hash_init(&ZCSG(hash), ZCG(accel_directives).max_accelerated_files); ZCSG(interned_strings_start) = ZCSG(interned_strings_end) = NULL; -# ifndef ZTS zend_hash_init(&ZCSG(interned_strings), (ZCG(accel_directives).interned_strings_buffer * 1024 * 1024) / _ZSTR_STRUCT_SIZE(8 /* average string length */), NULL, NULL, 1); if (ZCG(accel_directives).interned_strings_buffer) { void *data; @@ -2531,27 +2567,11 @@ static int zend_accel_init_shm(void) HT_HASH_RESET(&ZCSG(interned_strings)); ZCSG(interned_strings_end) = ZCSG(interned_strings_start) + (ZCG(accel_directives).interned_strings_buffer * 1024 * 1024); ZCSG(interned_strings_top) = ZCSG(interned_strings_start); - -// orig_interned_strings_start = CG(interned_strings_start); -// orig_interned_strings_end = CG(interned_strings_end); -// CG(interned_strings_start) = ZCSG(interned_strings_start); -// CG(interned_strings_end) = ZCSG(interned_strings_end); + ZCSG(interned_strings_saved_top) = NULL; + zend_interned_strings_set_permanent_storage_copy_handler(accel_use_shm_interned_strings); } -# endif - - orig_new_interned_string = zend_new_interned_string; - orig_interned_strings_snapshot = zend_interned_strings_snapshot; - orig_interned_strings_restore = zend_interned_strings_restore; - zend_new_interned_string = accel_new_interned_string_for_php; - zend_interned_strings_snapshot = accel_interned_strings_snapshot_for_php; - zend_interned_strings_restore = accel_interned_strings_restore_for_php; -# ifndef ZTS - if (ZCG(accel_directives).interned_strings_buffer) { - accel_use_shm_interned_strings(); - accel_interned_strings_save_state(); - } -# endif + zend_interned_strings_set_request_storage_handler(accel_new_interned_string_for_php); zend_reset_cache_vars(); @@ -2800,16 +2820,10 @@ static int accel_startup(zend_extension *extension) case SUCCESSFULLY_REATTACHED: zend_shared_alloc_lock(); accel_shared_globals = (zend_accel_shared_globals *) ZSMMG(app_shared_globals); - orig_new_interned_string = zend_new_interned_string; - orig_interned_strings_snapshot = zend_interned_strings_snapshot; - orig_interned_strings_restore = zend_interned_strings_restore; - - zend_new_interned_string = accel_new_interned_string_for_php; - zend_interned_strings_snapshot = accel_interned_strings_snapshot_for_php; - zend_interned_strings_restore = accel_interned_strings_restore_for_php; -#ifndef ZTS - accel_use_shm_interned_strings(); -#endif + if (ZCG(accel_directives).interned_strings_buffer) { + zend_interned_strings_set_permanent_storage_copy_handler(accel_use_shm_interned_strings); + } + zend_interned_strings_set_request_storage_handler(accel_new_interned_string_for_php); zend_shared_alloc_unlock(); break; case FAILED_REATTACHED: @@ -2929,25 +2943,16 @@ void accel_shutdown(void) return; } - if (ZCG(accel_directives).interned_strings_buffer) { -#ifndef ZTS - zend_hash_clean(CG(auto_globals)); - zend_hash_clean(CG(function_table)); - zend_hash_clean(CG(class_table)); - zend_hash_clean(EG(zend_constants)); +#ifdef HAVE_OPCACHE_FILE_CACHE + file_cache_only = ZCG(accel_directives).file_cache_only; #endif + + if (!file_cache_only && ZCG(accel_directives).interned_strings_buffer) { + accel_use_permanent_interned_strings(); } accel_reset_pcre_cache(); - zend_new_interned_string = orig_new_interned_string; - zend_interned_strings_snapshot = orig_interned_strings_snapshot; - zend_interned_strings_restore = orig_interned_strings_restore; - -#ifdef HAVE_OPCACHE_FILE_CACHE - file_cache_only = ZCG(accel_directives).file_cache_only; -#endif - accel_free_ts_resources(); if (!file_cache_only) { diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index 7d0f8dc861..59f3765fea 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -279,16 +279,13 @@ static zend_ast *zend_persist_ast(zend_ast *ast) static void zend_persist_zval(zval *z) { - zend_uchar flags; void *new_ptr; switch (Z_TYPE_P(z)) { case IS_STRING: case IS_CONSTANT: - flags = Z_GC_FLAGS_P(z) & ~ (IS_STR_PERSISTENT | IS_STR_INTERNED | IS_STR_PERMANENT); zend_accel_store_interned_string(Z_STR_P(z)); - Z_GC_FLAGS_P(z) |= flags; - Z_TYPE_FLAGS_P(z) &= ~IS_TYPE_REFCOUNTED; + Z_TYPE_FLAGS_P(z) &= ~ (IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE); break; case IS_ARRAY: new_ptr = zend_shared_alloc_get_xlat_entry(Z_ARR_P(z)); @@ -473,7 +470,7 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc ZEND_ASSERT(new_name != NULL); op_array->function_name = new_name; } else { - zend_accel_store_string(op_array->function_name); + zend_accel_store_interned_string(op_array->function_name); } } @@ -533,7 +530,7 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc op_array->doc_comment = zend_shared_alloc_get_xlat_entry(op_array->doc_comment); ZEND_ASSERT(op_array->doc_comment != NULL); } else { - zend_accel_store_string(op_array->doc_comment); + zend_accel_store_interned_string(op_array->doc_comment); } } else { if (!already_stored) { @@ -607,7 +604,7 @@ static void zend_persist_property_info(zval *zv) zend_accel_store_interned_string(prop->name); if (prop->doc_comment) { if (ZCG(accel_directives).save_comments) { - zend_accel_store_string(prop->doc_comment); + zend_accel_store_interned_string(prop->doc_comment); } else { if (!zend_shared_alloc_get_xlat_entry(prop->doc_comment)) { zend_shared_alloc_register_xlat_entry(prop->doc_comment, prop->doc_comment); @@ -638,7 +635,7 @@ static void zend_persist_class_constant(zval *zv) if (doc_comment) { c->doc_comment = doc_comment; } else { - zend_accel_store_string(c->doc_comment); + zend_accel_store_interned_string(c->doc_comment); } } else { zend_string *doc_comment = zend_shared_alloc_get_xlat_entry(c->doc_comment); @@ -688,7 +685,7 @@ static void zend_persist_class_entry(zval *zv) } if (ce->info.user.doc_comment) { if (ZCG(accel_directives).save_comments) { - zend_accel_store_string(ce->info.user.doc_comment); + zend_accel_store_interned_string(ce->info.user.doc_comment); } else { if (!zend_shared_alloc_get_xlat_entry(ce->info.user.doc_comment)) { zend_shared_alloc_register_xlat_entry(ce->info.user.doc_comment, ce->info.user.doc_comment); @@ -841,7 +838,7 @@ zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script if (key && *key) { *key = zend_accel_memdup(*key, key_length + 1); } - zend_accel_store_string(script->script.filename); + zend_accel_store_interned_string(script->script.filename); #ifdef __SSE2__ /* Align to 64-byte boundary */ diff --git a/ext/opcache/zend_persist_calc.c b/ext/opcache/zend_persist_calc.c index f169dffad1..cb7eb11b7a 100644 --- a/ext/opcache/zend_persist_calc.c +++ b/ext/opcache/zend_persist_calc.c @@ -83,9 +83,7 @@ static void zend_hash_persist_calc(HashTable *ht, void (*pPersistElement)(zval * /* persist bucket and key */ if (p->key) { - zend_uchar flags = GC_FLAGS(p->key) & ~ (IS_STR_PERSISTENT | IS_STR_INTERNED | IS_STR_PERMANENT); ADD_INTERNED_STRING(p->key, 1); - GC_FLAGS(p->key) |= flags; } pPersistElement(&p->val); @@ -120,18 +118,15 @@ static void zend_persist_ast_calc(zend_ast *ast) static void zend_persist_zval_calc(zval *z) { - zend_uchar flags; uint32_t size; switch (Z_TYPE_P(z)) { case IS_STRING: case IS_CONSTANT: - flags = Z_GC_FLAGS_P(z) & ~ (IS_STR_PERSISTENT | IS_STR_INTERNED | IS_STR_PERMANENT); ADD_INTERNED_STRING(Z_STR_P(z), 0); if (ZSTR_IS_INTERNED(Z_STR_P(z))) { Z_TYPE_FLAGS_P(z) &= ~ (IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE); } - Z_GC_FLAGS_P(z) |= flags; break; case IS_ARRAY: size = zend_shared_memdup_size(Z_ARR_P(z), sizeof(zend_array)); @@ -177,7 +172,7 @@ static void zend_persist_op_array_calc_ex(zend_op_array *op_array) /* already stored */ if (op_array->function_name) { zend_string *new_name = zend_shared_alloc_get_xlat_entry(op_array->function_name); - if (IS_ACCEL_INTERNED(new_name)) { + if (new_name) { op_array->function_name = new_name; } } diff --git a/ext/standard/array.c b/ext/standard/array.c index 3b2145d0fd..8b9ad196e4 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -2813,11 +2813,7 @@ PHP_FUNCTION(range) zend_hash_real_init(Z_ARRVAL_P(return_value), 1); ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) { for (; low >= high; low -= (unsigned int)lstep) { - if (CG(one_char_string)[low]) { - ZVAL_INTERNED_STR(&tmp, CG(one_char_string)[low]); - } else { - ZVAL_STRINGL(&tmp, (char*)&low, 1); - } + ZVAL_INTERNED_STR(&tmp, ZSTR_CHAR(low)); ZEND_HASH_FILL_ADD(&tmp); if (((signed int)low - lstep) < 0) { break; @@ -2833,11 +2829,7 @@ PHP_FUNCTION(range) zend_hash_real_init(Z_ARRVAL_P(return_value), 1); ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) { for (; low <= high; low += (unsigned int)lstep) { - if (CG(one_char_string)[low]) { - ZVAL_INTERNED_STR(&tmp, CG(one_char_string)[low]); - } else { - ZVAL_STRINGL(&tmp, (char*)&low, 1); - } + ZVAL_INTERNED_STR(&tmp, ZSTR_CHAR(low)); ZEND_HASH_FILL_ADD(&tmp); if (((signed int)low + lstep) > 255) { break; @@ -2846,11 +2838,7 @@ PHP_FUNCTION(range) } ZEND_HASH_FILL_END(); } else { array_init(return_value); - if (CG(one_char_string)[low]) { - ZVAL_INTERNED_STR(&tmp, CG(one_char_string)[low]); - } else { - ZVAL_STRINGL(&tmp, (char*)&low, 1); - } + ZVAL_INTERNED_STR(&tmp, ZSTR_CHAR(low)); zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp); } } else if (Z_TYPE_P(zlow) == IS_DOUBLE || Z_TYPE_P(zhigh) == IS_DOUBLE || is_step_double) { diff --git a/ext/standard/string.c b/ext/standard/string.c index c0120e1fc8..4ae3546d51 100644 --- a/ext/standard/string.c +++ b/ext/standard/string.c @@ -2766,13 +2766,7 @@ PHP_FUNCTION(chr) ZEND_PARSE_PARAMETERS_END_EX(c = 0); c &= 0xff; - if (CG(one_char_string)[c]) { - ZVAL_INTERNED_STR(return_value, CG(one_char_string)[c]); - } else { - ZVAL_NEW_STR(return_value, zend_string_alloc(1, 0)); - Z_STRVAL_P(return_value)[0] = (char)c; - Z_STRVAL_P(return_value)[1] = '\0'; - } + ZVAL_INTERNED_STR(return_value, ZSTR_CHAR(c)); } /* }}} */ @@ -4568,7 +4562,7 @@ PHP_FUNCTION(parse_str) symbol_table = zend_rebuild_symbol_table(); ZVAL_ARR(&tmp, symbol_table); sapi_module.treat_data(PARSE_STRING, res, &tmp); - if (UNEXPECTED(zend_hash_del(symbol_table, CG(known_strings)[ZEND_STR_THIS]) == SUCCESS)) { + if (UNEXPECTED(zend_hash_del(symbol_table, ZSTR_KNOWN(ZEND_STR_THIS)) == SUCCESS)) { zend_throw_error(NULL, "Cannot re-assign $this"); } } else { diff --git a/main/main.c b/main/main.c index 4e331ac2c8..723fd7d49b 100644 --- a/main/main.c +++ b/main/main.c @@ -1601,6 +1601,8 @@ int php_request_startup(void) { int retval = SUCCESS; + zend_interned_strings_activate(); + #ifdef HAVE_DTRACE DTRACE_REQUEST_STARTUP(SAFE_FILENAME(SG(request_info).path_translated), SAFE_FILENAME(SG(request_info).request_uri), (char *)SAFE_FILENAME(SG(request_info).request_method)); #endif /* HAVE_DTRACE */ @@ -1679,6 +1681,8 @@ int php_request_startup(void) { int retval = SUCCESS; + zend_interned_strings_activate(); + #if PHP_SIGCHILD signal(SIGCHLD, sigchld_handler); #endif @@ -1711,6 +1715,8 @@ int php_request_startup_for_hook(void) { int retval = SUCCESS; + zend_interned_strings_activate(); + #if PHP_SIGCHLD signal(SIGCHLD, sigchld_handler); #endif @@ -1734,8 +1740,8 @@ void php_request_shutdown_for_exec(void *dummy) /* used to close fd's in the 3..255 range here, but it's problematic */ + zend_interned_strings_deactivate(); shutdown_memory_manager(1, 1); - zend_interned_strings_restore(); } /* }}} */ @@ -1778,12 +1784,12 @@ void php_request_shutdown_for_hook(void *dummy) php_shutdown_stream_hashes(); } zend_end_try(); + zend_interned_strings_deactivate(); + zend_try { shutdown_memory_manager(CG(unclean_shutdown), 0); } zend_end_try(); - zend_interned_strings_restore(); - #ifdef ZEND_SIGNALS zend_try { zend_signal_deactivate(); @@ -1891,7 +1897,7 @@ void php_request_shutdown(void *dummy) } zend_end_try(); /* 15. Free Willy (here be crashes) */ - zend_interned_strings_restore(); + zend_interned_strings_deactivate(); zend_try { shutdown_memory_manager(CG(unclean_shutdown) || !report_memleaks, 0); } zend_end_try(); @@ -2357,9 +2363,10 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod module_startup = 0; shutdown_memory_manager(1, 0); - zend_interned_strings_snapshot(); virtual_cwd_activate(); + zend_interned_strings_switch_storage(); + /* we're done */ return retval; } diff --git a/main/streams/streams.c b/main/streams/streams.c index ed4b257848..4f9fabe434 100644 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -1706,7 +1706,7 @@ PHPAPI int php_register_url_stream_wrapper(const char *protocol, php_stream_wrap return FAILURE; } - return zend_hash_str_add_ptr(&url_stream_wrappers_hash, protocol, protocol_len, wrapper) ? SUCCESS : FAILURE; + return zend_hash_add_ptr(&url_stream_wrappers_hash, zend_string_init_interned(protocol, protocol_len, 1), wrapper) ? SUCCESS : FAILURE; } PHPAPI int php_unregister_url_stream_wrapper(const char *protocol) diff --git a/sapi/phpdbg/phpdbg.c b/sapi/phpdbg/phpdbg.c index b45ef3f684..f6008c22f1 100644 --- a/sapi/phpdbg/phpdbg.c +++ b/sapi/phpdbg/phpdbg.c @@ -811,15 +811,11 @@ static zend_module_entry sapi_phpdbg_module_entry = { STANDARD_MODULE_PROPERTIES }; -static void phpdbg_interned_strings_nothing(void) { } - static inline int php_sapi_phpdbg_module_startup(sapi_module_struct *module) /* {{{ */ { if (php_module_startup(module, &sapi_phpdbg_module_entry, 1) == FAILURE) { return FAILURE; } - /* prevent zend_interned_strings_restore from invalidating our string pointers too early (in phpdbg allocated memory only gets freed after module shutdown) */ - zend_interned_strings_restore = phpdbg_interned_strings_nothing; phpdbg_booted = 1; |