summaryrefslogtreecommitdiff
path: root/Zend
diff options
context:
space:
mode:
Diffstat (limited to 'Zend')
-rw-r--r--Zend/zend.c14
-rw-r--r--Zend/zend_API.c4
-rw-r--r--Zend/zend_builtin_functions.c52
-rw-r--r--Zend/zend_closures.c6
-rw-r--r--Zend/zend_compile.c14
-rw-r--r--Zend/zend_constants.c4
-rw-r--r--Zend/zend_exceptions.c68
-rw-r--r--Zend/zend_execute.c12
-rw-r--r--Zend/zend_execute_API.c2
-rw-r--r--Zend/zend_globals.h5
-rw-r--r--Zend/zend_ini.c2
-rw-r--r--Zend/zend_language_parser.y2
-rw-r--r--Zend/zend_object_handlers.c2
-rw-r--r--Zend/zend_operators.c45
-rw-r--r--Zend/zend_string.c302
-rw-r--r--Zend/zend_string.h56
-rw-r--r--Zend/zend_vm_def.h10
-rw-r--r--Zend/zend_vm_execute.h24
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 *) &not, 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) {