diff options
Diffstat (limited to 'Zend')
-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 |
18 files changed, 290 insertions, 334 deletions
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) { |