diff --git a/Zend/Optimizer/block_pass.c b/Zend/Optimizer/block_pass.c index 02c28ead33e1..d6baf32bb961 100644 --- a/Zend/Optimizer/block_pass.c +++ b/Zend/Optimizer/block_pass.c @@ -31,6 +31,11 @@ bool zend_optimizer_get_persistent_constant(zend_string *name, zval *result, bool copy) { const zend_constant *c = zend_hash_find_ptr(EG(zend_constants), name); +#ifdef ZTS + if (!c) { + c = zend_hash_find_ptr(zend_global_constants_table, name); + } +#endif if (c) { if ((ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT) && !(ZEND_CONSTANT_FLAGS(c) & CONST_DEPRECATED) diff --git a/Zend/zend.c b/Zend/zend.c index 07692db85196..525f204900d4 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -59,13 +59,12 @@ ZEND_API size_t executor_globals_offset; static void *language_scanner_globals_tls_addr(void) { return &language_scanner_globals; } static HashTable *global_function_table = NULL; static HashTable *global_class_table = NULL; -static HashTable *global_constants_table = NULL; static HashTable *global_auto_globals_table = NULL; static HashTable *global_persistent_list = NULL; TSRMLS_MAIN_CACHE_DEFINE() # define GLOBAL_FUNCTION_TABLE global_function_table # define GLOBAL_CLASS_TABLE global_class_table -# define GLOBAL_CONSTANTS_TABLE global_constants_table +# define GLOBAL_CONSTANTS_TABLE zend_global_constants_table # define GLOBAL_AUTO_GLOBALS_TABLE global_auto_globals_table #else # define GLOBAL_FUNCTION_TABLE CG(function_table) @@ -715,19 +714,34 @@ static void auto_global_copy_ctor(zval *zv) /* {{{ */ } /* }}} */ +/* Copy the source's bucket array as-is instead of copying entries one by one. + * The source must be frozen and contiguous. Entries remain owned by the + * source table and must not be destroyed with the copy, so + * compiler_globals_dtor() undefs them first. */ +static HashTable *zend_hash_clone_persistent(const HashTable *source) +{ + HashTable *ht = (HashTable *) malloc(sizeof(HashTable)); + + if (source->nNumUsed == 0) { + zend_hash_init(ht, source->nTableSize, NULL, source->pDestructor, 1); + } else { + *ht = *source; + HT_SET_DATA_ADDR(ht, pemalloc(HT_SIZE(ht), 1)); + memcpy(HT_GET_DATA_ADDR(ht), HT_GET_DATA_ADDR(source), HT_USED_SIZE(source)); + } + return ht; +} + static void compiler_globals_ctor(zend_compiler_globals *compiler_globals) /* {{{ */ { compiler_globals->compiled_filename = NULL; compiler_globals->zend_lineno = 0; - compiler_globals->function_table = (HashTable *) malloc(sizeof(HashTable)); - zend_hash_init(compiler_globals->function_table, 1024, NULL, ZEND_FUNCTION_DTOR, 1); - zend_hash_copy(compiler_globals->function_table, global_function_table, NULL); + compiler_globals->function_table = zend_hash_clone_persistent(global_function_table); compiler_globals->copied_functions_count = zend_hash_num_elements(compiler_globals->function_table); - compiler_globals->class_table = (HashTable *) malloc(sizeof(HashTable)); - zend_hash_init(compiler_globals->class_table, 64, NULL, ZEND_CLASS_DTOR, 1); - zend_hash_copy(compiler_globals->class_table, global_class_table, zend_class_add_ref); + compiler_globals->class_table = zend_hash_clone_persistent(global_class_table); + compiler_globals->copied_classes_count = zend_hash_num_elements(compiler_globals->class_table); zend_set_default_compile_time_values(); @@ -778,6 +792,21 @@ static void compiler_globals_dtor(zend_compiler_globals *compiler_globals) /* {{ free(compiler_globals->function_table); } if (compiler_globals->class_table != GLOBAL_CLASS_TABLE) { + uint32_t n = compiler_globals->copied_classes_count; + + /* Prevent destruction of classes copied from the main process context */ + if (zend_hash_num_elements(compiler_globals->class_table) <= n) { + compiler_globals->class_table->nNumUsed = 0; + } else { + Bucket *p = compiler_globals->class_table->arData; + + compiler_globals->class_table->nNumOfElements -= n; + while (n != 0) { + ZVAL_UNDEF(&p->val); + p++; + n--; + } + } /* Child classes may reuse structures from parent classes, so destroy in reverse order. */ zend_hash_graceful_reverse_destroy(compiler_globals->class_table); free(compiler_globals->class_table); @@ -805,7 +834,6 @@ static void compiler_globals_dtor(zend_compiler_globals *compiler_globals) /* {{ static void executor_globals_ctor(zend_executor_globals *executor_globals) /* {{{ */ { zend_startup_constants(); - zend_copy_constants(executor_globals->zend_constants, GLOBAL_CONSTANTS_TABLE); zend_init_rsrc_plist(); zend_init_exception_op(); zend_init_call_trampoline_op(); @@ -1041,7 +1069,8 @@ void zend_startup(zend_utility_functions *utility_functions) /* {{{ */ compiler_globals->auto_globals = GLOBAL_AUTO_GLOBALS_TABLE; zend_hash_destroy(executor_globals->zend_constants); - *executor_globals->zend_constants = *GLOBAL_CONSTANTS_TABLE; + free(executor_globals->zend_constants); + executor_globals->zend_constants = GLOBAL_CONSTANTS_TABLE; #else ini_scanner_globals_ctor(&ini_scanner_globals); php_scanner_globals_ctor(&language_scanner_globals); @@ -1096,6 +1125,31 @@ void zend_register_standard_ini_entries(void) /* {{{ */ /* }}} */ +#ifdef ZTS +/* All threads read constants from GLOBAL_CONSTANTS_TABLE without copying or + * refcounting, so any string still not interned at this point must be made + * immortal. In practice registration interns everything and this is a no-op. */ +static void zend_share_persistent_constants(void) +{ + zend_constant *c; + + ZEND_HASH_MAP_FOREACH_PTR(GLOBAL_CONSTANTS_TABLE, c) { + if (!(ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT)) { + continue; + } + if (!ZSTR_IS_INTERNED(c->name)) { + GC_ADD_FLAGS(c->name, IS_STR_INTERNED | IS_STR_PERMANENT); + } + if (c->filename && !ZSTR_IS_INTERNED(c->filename)) { + GC_ADD_FLAGS(c->filename, IS_STR_INTERNED | IS_STR_PERMANENT); + } + if (Z_TYPE(c->value) == IS_STRING && !ZSTR_IS_INTERNED(Z_STR(c->value))) { + GC_ADD_FLAGS(Z_STR(c->value), IS_STR_INTERNED | IS_STR_PERMANENT); + } + } ZEND_HASH_FOREACH_END(); +} +#endif + /* Unlink the global (r/o) copies of the class, function and constant tables, * and use a fresh r/w copy for the startup thread */ @@ -1122,7 +1176,11 @@ zend_result zend_post_startup(void) /* {{{ */ #ifdef ZTS *GLOBAL_FUNCTION_TABLE = *compiler_globals->function_table; *GLOBAL_CLASS_TABLE = *compiler_globals->class_table; - *GLOBAL_CONSTANTS_TABLE = *executor_globals->zend_constants; + /* zend_hash_clone_persistent() requires hole-free sources; disable_functions + * etc. may have deleted entries. The tables are frozen from here on. */ + zend_hash_rehash(GLOBAL_FUNCTION_TABLE); + zend_hash_rehash(GLOBAL_CLASS_TABLE); + zend_share_persistent_constants(); global_map_ptr_last = compiler_globals->map_ptr_last; short_tags_default = CG(short_tags); @@ -1148,7 +1206,8 @@ zend_result zend_post_startup(void) /* {{{ */ } else { compiler_globals_ctor(compiler_globals); } - free(EG(zend_constants)); + /* Aliases GLOBAL_CONSTANTS_TABLE; the ctor allocates this thread's own + * (empty) table for runtime constants. */ EG(zend_constants) = NULL; executor_globals_ctor(executor_globals); diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 87acf073a2da..0f9eeb14be6f 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -1632,6 +1632,9 @@ ZEND_FUNCTION(get_defined_constants) array_init(return_value); + HashTable *const_tables[2]; + unsigned int num_const_tables = zend_get_constants_tables(const_tables); + if (categorize) { zend_constant *val; int module_number; @@ -1650,29 +1653,31 @@ ZEND_FUNCTION(get_defined_constants) } ZEND_HASH_FOREACH_END(); module_names[i] = "user"; - ZEND_HASH_MAP_FOREACH_PTR(EG(zend_constants), val) { - if (!val->name) { - /* skip special constants */ - continue; - } + for (unsigned int t = 0; t < num_const_tables; t++) { + ZEND_HASH_MAP_FOREACH_PTR(const_tables[t], val) { + if (!val->name) { + /* skip special constants */ + continue; + } - if (ZEND_CONSTANT_MODULE_NUMBER(val) == PHP_USER_CONSTANT) { - module_number = i; - } else if (ZEND_CONSTANT_MODULE_NUMBER(val) > i) { - /* should not happen */ - continue; - } else { - module_number = ZEND_CONSTANT_MODULE_NUMBER(val); - } + if (ZEND_CONSTANT_MODULE_NUMBER(val) == PHP_USER_CONSTANT) { + module_number = i; + } else if (ZEND_CONSTANT_MODULE_NUMBER(val) > i) { + /* should not happen */ + continue; + } else { + module_number = ZEND_CONSTANT_MODULE_NUMBER(val); + } - if (Z_TYPE(modules[module_number]) == IS_UNDEF) { - array_init(&modules[module_number]); - add_assoc_zval(return_value, module_names[module_number], &modules[module_number]); - } + if (Z_TYPE(modules[module_number]) == IS_UNDEF) { + array_init(&modules[module_number]); + add_assoc_zval(return_value, module_names[module_number], &modules[module_number]); + } - ZVAL_COPY_OR_DUP(&const_val, &val->value); - zend_hash_add_new(Z_ARRVAL(modules[module_number]), val->name, &const_val); - } ZEND_HASH_FOREACH_END(); + ZVAL_COPY_OR_DUP(&const_val, &val->value); + zend_hash_add_new(Z_ARRVAL(modules[module_number]), val->name, &const_val); + } ZEND_HASH_FOREACH_END(); + } efree(module_names); efree(modules); @@ -1680,14 +1685,16 @@ ZEND_FUNCTION(get_defined_constants) zend_constant *constant; zval const_val; - ZEND_HASH_MAP_FOREACH_PTR(EG(zend_constants), constant) { - if (!constant->name) { - /* skip special constants */ - continue; - } - ZVAL_COPY_OR_DUP(&const_val, &constant->value); - zend_hash_add_new(Z_ARRVAL_P(return_value), constant->name, &const_val); - } ZEND_HASH_FOREACH_END(); + for (unsigned int t = 0; t < num_const_tables; t++) { + ZEND_HASH_MAP_FOREACH_PTR(const_tables[t], constant) { + if (!constant->name) { + /* skip special constants */ + continue; + } + ZVAL_COPY_OR_DUP(&const_val, &constant->value); + zend_hash_add_new(Z_ARRVAL_P(return_value), constant->name, &const_val); + } ZEND_HASH_FOREACH_END(); + } } } /* }}} */ diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index ac5a9d71a6ea..a86d6879f9ff 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1705,6 +1705,11 @@ static bool zend_try_ct_eval_const(zval *zv, zend_string *name, bool is_fully_qu return true; } c = zend_hash_find_ptr(EG(zend_constants), name); +#ifdef ZTS + if (!c) { + c = zend_hash_find_ptr(zend_global_constants_table, name); + } +#endif if (c && can_ct_eval_const(c)) { ZVAL_COPY_OR_DUP(zv, &c->value); return true; diff --git a/Zend/zend_constants.c b/Zend/zend_constants.c index 18292203bee9..17a31206ab4b 100644 --- a/Zend/zend_constants.c +++ b/Zend/zend_constants.c @@ -70,33 +70,10 @@ void free_zend_constant(zval *zv) #ifdef ZTS -static void copy_zend_constant(zval *zv) -{ - zend_constant *c = Z_PTR_P(zv); - - ZEND_ASSERT(ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT); - Z_PTR_P(zv) = pemalloc(sizeof(zend_constant), 1); - memcpy(Z_PTR_P(zv), c, sizeof(zend_constant)); - - c = Z_PTR_P(zv); - c->name = zend_string_copy(c->name); - if (c->filename != NULL) { - c->filename = zend_string_copy(c->filename); - } - if (c->attributes != NULL) { - // Use the same attributes table - GC_ADDREF(c->attributes); - } - if (Z_TYPE(c->value) == IS_STRING) { - Z_STR(c->value) = zend_string_dup(Z_STR(c->value), 1); - } -} - - -void zend_copy_constants(HashTable *target, HashTable *source) -{ - zend_hash_copy(target, source, copy_zend_constant); -} +/* Persistent constants live only in this shared table. Per-thread + * EG(zend_constants) holds runtime-defined constants. During startup the + * main thread's EG(zend_constants) aliases this table. */ +ZEND_API HashTable *zend_global_constants_table = NULL; #endif @@ -265,10 +242,25 @@ ZEND_API bool zend_verify_const_access(const zend_class_constant *c, const zend_ static zend_constant *zend_get_constant_str_impl(const char *name, size_t name_len) { +#ifdef ZTS + /* Skip the per-thread table while no run-time constant has been + * defined (the common case); persistent constants live only in the + * shared global table. */ + zend_constant *c = zend_hash_num_elements(EG(zend_constants)) + ? zend_hash_str_find_ptr(EG(zend_constants), name, name_len) : NULL; + if (c) { + return c; + } + c = zend_hash_str_find_ptr(zend_global_constants_table, name, name_len); + if (c) { + return c; + } +#else zend_constant *c = zend_hash_str_find_ptr(EG(zend_constants), name, name_len); if (c) { return c; } +#endif c = zend_get_halt_offset_constant(name, name_len); if (c) { @@ -289,10 +281,22 @@ ZEND_API zval *zend_get_constant_str(const char *name, size_t name_len) ZEND_API zend_constant *zend_get_constant_ptr(zend_string *name) { +#ifdef ZTS + zend_constant *c = zend_hash_num_elements(EG(zend_constants)) + ? zend_hash_find_ptr(EG(zend_constants), name) : NULL; + if (c) { + return c; + } + c = zend_hash_find_ptr(zend_global_constants_table, name); + if (c) { + return c; + } +#else zend_constant *c = zend_hash_find_ptr(EG(zend_constants), name); if (c) { return c; } +#endif c = zend_get_halt_offset_constant(ZSTR_VAL(name), ZSTR_LEN(name)); if (c) { @@ -458,6 +462,11 @@ ZEND_API zval *zend_get_constant_ex(zend_string *cname, const zend_class_entry * memcpy(lcname + prefix_len + 1, constant_name, const_name_len + 1); c = zend_hash_str_find_ptr(EG(zend_constants), lcname, lcname_len); +#ifdef ZTS + if (!c) { + c = zend_hash_str_find_ptr(zend_global_constants_table, lcname, lcname_len); + } +#endif free_alloca(lcname, use_heap); if (!c) { @@ -541,6 +550,10 @@ ZEND_API zend_constant *zend_register_constant(zend_constant *c) /* Check if the user is trying to define any special constant */ if (zend_string_equals_literal(name, "__COMPILER_HALT_OFFSET__") || (!persistent && zend_get_special_const(ZSTR_VAL(name), ZSTR_LEN(name))) +#ifdef ZTS + || (EG(zend_constants) != zend_global_constants_table + && zend_hash_exists(zend_global_constants_table, name)) +#endif || (ret = zend_hash_add_constant(EG(zend_constants), name, c)) == NULL ) { zend_error(E_WARNING, "Constant %s already defined, this will be an error in PHP 9", ZSTR_VAL(name)); diff --git a/Zend/zend_constants.h b/Zend/zend_constants.h index 9461ac764c90..8e0dd553e8f5 100644 --- a/Zend/zend_constants.h +++ b/Zend/zend_constants.h @@ -99,9 +99,36 @@ ZEND_API zend_constant *zend_register_stringl_constant(const char *name, size_t ZEND_API zend_constant *zend_register_constant(zend_constant *c); void zend_constant_add_attributes(zend_constant *c, HashTable *attributes); #ifdef ZTS -void zend_copy_constants(HashTable *target, HashTable *source); +extern ZEND_API HashTable *zend_global_constants_table; #endif +/* Tables to scan for a full view of all defined constants, in definition + * order. In ZTS this is the shared persistent table followed by the + * per-thread table (unless they alias during startup). */ +static zend_always_inline unsigned int zend_get_constants_tables(HashTable **tables) +{ +#ifdef ZTS + if (EXPECTED(zend_global_constants_table != EG(zend_constants))) { + tables[0] = zend_global_constants_table; + tables[1] = EG(zend_constants); + return 2; + } +#endif + tables[0] = EG(zend_constants); + return 1; +} + +static zend_always_inline uint32_t zend_get_constants_count(void) +{ + uint32_t count = zend_hash_num_elements(EG(zend_constants)); +#ifdef ZTS + if (EXPECTED(zend_global_constants_table != EG(zend_constants))) { + count += zend_hash_num_elements(zend_global_constants_table); + } +#endif + return count; +} + ZEND_API zend_constant *_zend_get_special_const(const char *name, size_t name_len); static zend_always_inline zend_constant *zend_get_special_const( diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 1b28ce25fe37..d015e6253378 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -5438,12 +5438,29 @@ static zend_always_inline zend_result _zend_quick_get_constant( zend_constant *c = NULL; /* null/true/false are resolved during compilation, so don't check for them here. */ +#ifdef ZTS + /* Skip the per-thread table while no run-time constant is defined. */ + zv = zend_hash_num_elements(EG(zend_constants)) + ? zend_hash_find_known_hash(EG(zend_constants), Z_STR_P(key)) : NULL; + if (!zv) { + zv = zend_hash_find_known_hash(zend_global_constants_table, Z_STR_P(key)); + } +#else zv = zend_hash_find_known_hash(EG(zend_constants), Z_STR_P(key)); +#endif if (zv) { c = (zend_constant*)Z_PTR_P(zv); } else if (flags & IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE) { key++; +#ifdef ZTS + zv = zend_hash_num_elements(EG(zend_constants)) + ? zend_hash_find_known_hash(EG(zend_constants), Z_STR_P(key)) : NULL; + if (!zv) { + zv = zend_hash_find_known_hash(zend_global_constants_table, Z_STR_P(key)); + } +#else zv = zend_hash_find_known_hash(EG(zend_constants), Z_STR_P(key)); +#endif if (zv) { c = (zend_constant*)Z_PTR_P(zv); } diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index f78567cfaa74..7b594367c782 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -166,6 +166,7 @@ struct _zend_compiler_globals { zend_stack short_circuiting_opnums; #ifdef ZTS uint32_t copied_functions_count; + uint32_t copied_classes_count; #endif }; diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index fbbfab6b243c..a4410c38415f 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -552,11 +552,21 @@ static bool zend_jit_is_persistent_constant(zval *key, uint32_t flags) /* null/true/false are resolved during compilation, so don't check for them here. */ zv = zend_hash_find_known_hash(EG(zend_constants), Z_STR_P(key)); +#ifdef ZTS + if (!zv) { + zv = zend_hash_find_known_hash(zend_global_constants_table, Z_STR_P(key)); + } +#endif if (zv) { c = (zend_constant*)Z_PTR_P(zv); } else if (flags & IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE) { key++; zv = zend_hash_find_known_hash(EG(zend_constants), Z_STR_P(key)); +#ifdef ZTS + if (!zv) { + zv = zend_hash_find_known_hash(zend_global_constants_table, Z_STR_P(key)); + } +#endif if (zv) { c = (zend_constant*)Z_PTR_P(zv); } diff --git a/ext/opcache/jit/zend_jit_vm_helpers.c b/ext/opcache/jit/zend_jit_vm_helpers.c index 85a81c1573bc..5486962f1712 100644 --- a/ext/opcache/jit/zend_jit_vm_helpers.c +++ b/ext/opcache/jit/zend_jit_vm_helpers.c @@ -410,11 +410,21 @@ static zend_always_inline zend_constant* _zend_quick_get_constant( /* null/true/false are resolved during compilation, so don't check for them here. */ zv = zend_hash_find_known_hash(EG(zend_constants), Z_STR_P(key)); +#ifdef ZTS + if (!zv) { + zv = zend_hash_find_known_hash(zend_global_constants_table, Z_STR_P(key)); + } +#endif if (zv) { c = (zend_constant*)Z_PTR_P(zv); } else if (flags & IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE) { key++; zv = zend_hash_find_known_hash(EG(zend_constants), Z_STR_P(key)); +#ifdef ZTS + if (!zv) { + zv = zend_hash_find_known_hash(zend_global_constants_table, Z_STR_P(key)); + } +#endif if (zv) { c = (zend_constant*)Z_PTR_P(zv); } diff --git a/ext/readline/readline_cli.c b/ext/readline/readline_cli.c index 3b2a08a15843..28ea6c41e424 100644 --- a/ext/readline/readline_cli.c +++ b/ext/readline/readline_cli.c @@ -31,6 +31,7 @@ #include "php_ini.h" #include "ext/standard/info.h" #include "zend_smart_str.h" +#include "zend_constants.h" #ifdef __riscos__ #include @@ -557,13 +558,31 @@ static char *cli_completion_generator(const char *text, int index) /* {{{ */ ZEND_FALLTHROUGH; case 2: case 3: +#ifdef ZTS + retval = cli_completion_generator_define(text, textlen, &cli_completion_state, ce ? &ce->constants_table : zend_global_constants_table); +#else retval = cli_completion_generator_define(text, textlen, &cli_completion_state, ce ? &ce->constants_table : EG(zend_constants)); +#endif if (retval || ce) { break; } ZEND_FALLTHROUGH; +#ifdef ZTS case 4: case 5: + if (!ce) { + retval = cli_completion_generator_define(text, textlen, &cli_completion_state, EG(zend_constants)); + } + if (retval || ce) { + break; + } + ZEND_FALLTHROUGH; + case 6: + case 7: +#else + case 4: + case 5: +#endif retval = cli_completion_generator_class(lc_text, textlen, &cli_completion_state); break; default: diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 50054d4c1106..e481f1d2e2c1 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -1211,13 +1211,17 @@ static void _extension_string(smart_str *str, const zend_module_entry *module) / smart_str str_constants = {0}; zend_constant *constant; int num_constants = 0; - - ZEND_HASH_MAP_FOREACH_PTR(EG(zend_constants), constant) { - if (ZEND_CONSTANT_MODULE_NUMBER(constant) == module->module_number) { - _const_string(&str_constants, constant->name, &constant->value, " "); - num_constants++; - } - } ZEND_HASH_FOREACH_END(); + HashTable *const_tables[2]; + unsigned int num_const_tables = zend_get_constants_tables(const_tables); + + for (unsigned int t = 0; t < num_const_tables; t++) { + ZEND_HASH_MAP_FOREACH_PTR(const_tables[t], constant) { + if (ZEND_CONSTANT_MODULE_NUMBER(constant) == module->module_number) { + _const_string(&str_constants, constant->name, &constant->value, " "); + num_constants++; + } + } ZEND_HASH_FOREACH_END(); + } if (num_constants) { smart_str_append_printf(str, "\n - Constants [%d] {\n", num_constants); @@ -7030,13 +7034,17 @@ ZEND_METHOD(ReflectionExtension, getConstants) GET_REFLECTION_OBJECT_PTR(module); array_init(return_value); - ZEND_HASH_MAP_FOREACH_PTR(EG(zend_constants), constant) { - if (module->module_number == ZEND_CONSTANT_MODULE_NUMBER(constant)) { - zval const_val; - ZVAL_COPY_OR_DUP(&const_val, &constant->value); - zend_hash_update(Z_ARRVAL_P(return_value), constant->name, &const_val); - } - } ZEND_HASH_FOREACH_END(); + HashTable *const_tables[2]; + unsigned int num_const_tables = zend_get_constants_tables(const_tables); + for (unsigned int t = 0; t < num_const_tables; t++) { + ZEND_HASH_MAP_FOREACH_PTR(const_tables[t], constant) { + if (module->module_number == ZEND_CONSTANT_MODULE_NUMBER(constant)) { + zval const_val; + ZVAL_COPY_OR_DUP(&const_val, &constant->value); + zend_hash_update(Z_ARRVAL_P(return_value), constant->name, &const_val); + } + } ZEND_HASH_FOREACH_END(); + } } /* }}} */ diff --git a/sapi/phpdbg/phpdbg.c b/sapi/phpdbg/phpdbg.c index 3c0d5e836dd0..19a1c3f98ce9 100644 --- a/sapi/phpdbg/phpdbg.c +++ b/sapi/phpdbg/phpdbg.c @@ -20,6 +20,7 @@ #include "phpdbg_break.h" #include "phpdbg_list.h" #include "phpdbg_utils.h" +#include "zend_constants.h" #include "phpdbg_set.h" #include "phpdbg_io.h" #include "zend_alloc.h" @@ -997,7 +998,7 @@ static void phpdbg_welcome(bool cleaning) /* {{{ */ "Includes %d\n", zend_hash_num_elements(EG(class_table)), zend_hash_num_elements(EG(function_table)), - zend_hash_num_elements(EG(zend_constants)), + zend_get_constants_count(), zend_hash_num_elements(&EG(included_files))); } } /* }}} */ diff --git a/sapi/phpdbg/phpdbg_prompt.c b/sapi/phpdbg/phpdbg_prompt.c index d6249ae068da..83a90e7e813b 100644 --- a/sapi/phpdbg/phpdbg_prompt.c +++ b/sapi/phpdbg/phpdbg_prompt.c @@ -20,6 +20,7 @@ #include "zend_compile.h" #include "zend_exceptions.h" #include "zend_vm.h" +#include "zend_constants.h" #include "zend_generators.h" #include "zend_interfaces.h" #include "zend_smart_str.h" @@ -1093,7 +1094,7 @@ PHPDBG_COMMAND(info) /* {{{ */ phpdbg_writeln("Classes %d", zend_hash_num_elements(EG(class_table))); phpdbg_writeln("Functions %d", zend_hash_num_elements(EG(function_table))); - phpdbg_writeln("Constants %d", zend_hash_num_elements(EG(zend_constants))); + phpdbg_writeln("Constants %d", zend_get_constants_count()); phpdbg_writeln("Included %d", zend_hash_num_elements(&EG(included_files))); return SUCCESS; @@ -1436,7 +1437,7 @@ PHPDBG_COMMAND(clean) /* {{{ */ phpdbg_writeln("Classes %d", zend_hash_num_elements(EG(class_table))); phpdbg_writeln("Functions %d", zend_hash_num_elements(EG(function_table))); - phpdbg_writeln("Constants %d", zend_hash_num_elements(EG(zend_constants))); + phpdbg_writeln("Constants %d", zend_get_constants_count()); phpdbg_writeln("Includes %d", zend_hash_num_elements(&EG(included_files))); phpdbg_clean(1, 0);