From e78a7b0b2fcd5d6d923f545929654bab9b0e2c51 Mon Sep 17 00:00:00 2001 From: ndossche <7771979+ndossche@users.noreply.github.com> Date: Tue, 23 Jun 2026 00:01:42 +0200 Subject: [PATCH] Implement zend_enum_get_case_by_id() Avoid hash-based lookup if we already know the offset in the table anyway. --- UPGRADING.INTERNALS | 1 + Zend/zend_enum.c | 5 +++++ Zend/zend_enum.h | 1 + ext/pcntl/pcntl.c | 15 ++++++++------- ext/standard/io_poll.c | 22 ++++++++-------------- ext/uri/uri_parser_rfc3986.c | 24 ++++++++++++------------ ext/zend_test/test.c | 3 ++- main/streams/stream_errors.c | 1 + 8 files changed, 38 insertions(+), 34 deletions(-) diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index 1f24fb82fcf9..2f0d016a99cd 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -65,6 +65,7 @@ PHP 8.6 INTERNALS UPGRADE NOTES zend_enum_RoundingMode parameter. . Added Z_PARAM_ENUM(). . Added zend_enum_fetch_case_id(). + . Added zend_enum_get_case_by_id(). . ZEND_INI_GET_ADDR() is now a void* pointer instead of a char* pointer. This more correctly represents the generic nature of the returned pointer and allows to remove explicit casts, but possibly breaks pointer arithmetic diff --git a/Zend/zend_enum.c b/Zend/zend_enum.c index 7f0b58575387..ecebe7a5d51b 100644 --- a/Zend/zend_enum.c +++ b/Zend/zend_enum.c @@ -673,6 +673,11 @@ ZEND_API zend_object *zend_enum_get_case_cstr(zend_class_entry *ce, const char * return zend_enum_case_from_class_constant(c); } +ZEND_API zend_object *zend_enum_get_case_by_id(zend_class_entry *ce, int id) { + zend_class_constant *c = Z_PTR(CE_CONSTANTS_TABLE(ce)->arData[id - 1].val); + return zend_enum_case_from_class_constant(c); +} + void zend_enum_startup(void) { for (size_t i = 0; i < sizeof(zarginfo_class_UnitEnum_cases)/sizeof(zend_arg_info); i++) { diff --git a/Zend/zend_enum.h b/Zend/zend_enum.h index 6bffb8866507..f252c938eb83 100644 --- a/Zend/zend_enum.h +++ b/Zend/zend_enum.h @@ -55,6 +55,7 @@ ZEND_API void zend_enum_add_case(zend_class_entry *ce, zend_string *case_name, z ZEND_API void zend_enum_add_case_cstr(zend_class_entry *ce, const char *name, zval *value); ZEND_API zend_object *zend_enum_get_case(zend_class_entry *ce, zend_string *name); ZEND_API zend_object *zend_enum_get_case_cstr(zend_class_entry *ce, const char *name); +ZEND_API zend_object *zend_enum_get_case_by_id(zend_class_entry *ce, int id); ZEND_API zend_result zend_enum_get_case_by_value(zend_object **result, zend_class_entry *ce, zend_long long_key, zend_string *string_key, bool try_from); static zend_always_inline int zend_enum_fetch_case_id(zend_object *zobj) diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c index 2ba732c4540e..794e75a1716e 100644 --- a/ext/pcntl/pcntl.c +++ b/ext/pcntl/pcntl.c @@ -152,6 +152,7 @@ typedef psetid_t cpu_set_t; #include "Zend/zend_max_execution_timer.h" #include "pcntl_arginfo.h" +#include "pcntl_decl.h" static zend_class_entry *QosClass_ce; ZEND_DECLARE_MODULE_GLOBALS(pcntl) @@ -1839,28 +1840,28 @@ static qos_class_t qos_enum_to_pthread(zend_enum_Pcntl_QosClass entry) static zend_object *qos_lval_to_zval(qos_class_t qos_class) { - const char *entryname; + int entry_id; switch (qos_class) { case QOS_CLASS_USER_INTERACTIVE: - entryname = "UserInteractive"; + entry_id = ZEND_ENUM_Pcntl_QosClass_UserInteractive; break; case QOS_CLASS_USER_INITIATED: - entryname = "UserInitiated"; + entry_id = ZEND_ENUM_Pcntl_QosClass_UserInitiated; break; case QOS_CLASS_UTILITY: - entryname = "Utility"; + entry_id = ZEND_ENUM_Pcntl_QosClass_Utility; break; case QOS_CLASS_BACKGROUND: - entryname = "Background"; + entry_id = ZEND_ENUM_Pcntl_QosClass_Background; break; case QOS_CLASS_DEFAULT: default: - entryname = "Default"; + entry_id = ZEND_ENUM_Pcntl_QosClass_Default; break; } - return zend_enum_get_case_cstr(QosClass_ce, entryname); + return zend_enum_get_case_by_id(QosClass_ce, entry_id); } PHP_FUNCTION(pcntl_getqos_class) diff --git a/ext/standard/io_poll.c b/ext/standard/io_poll.c index b1eb7513f1cb..837470a9f753 100644 --- a/ext/standard/io_poll.c +++ b/ext/standard/io_poll.c @@ -18,6 +18,7 @@ #include "php_network.h" #include "php_poll.h" #include "io_poll_arginfo.h" +#include "io_poll_decl.h" /* Class entries */ static zend_class_entry *php_io_poll_backend_class_entry; @@ -118,38 +119,31 @@ static zend_result php_io_poll_events_to_event_enums(uint32_t events, zval *even array_init(event_enums); if (events & PHP_POLL_READ) { - ZVAL_OBJ(&enum_case, zend_enum_get_case_cstr(php_io_poll_event_class_entry, "Read")); - GC_ADDREF(Z_OBJ(enum_case)); + ZVAL_OBJ_COPY(&enum_case, zend_enum_get_case_by_id(php_io_poll_event_class_entry, ZEND_ENUM_Io_Poll_Event_Read)); add_next_index_zval(event_enums, &enum_case); } if (events & PHP_POLL_WRITE) { - ZVAL_OBJ(&enum_case, zend_enum_get_case_cstr(php_io_poll_event_class_entry, "Write")); - GC_ADDREF(Z_OBJ(enum_case)); + ZVAL_OBJ_COPY(&enum_case, zend_enum_get_case_by_id(php_io_poll_event_class_entry, ZEND_ENUM_Io_Poll_Event_Write)); add_next_index_zval(event_enums, &enum_case); } if (events & PHP_POLL_ERROR) { - ZVAL_OBJ(&enum_case, zend_enum_get_case_cstr(php_io_poll_event_class_entry, "Error")); - GC_ADDREF(Z_OBJ(enum_case)); + ZVAL_OBJ_COPY(&enum_case, zend_enum_get_case_by_id(php_io_poll_event_class_entry, ZEND_ENUM_Io_Poll_Event_Error)); add_next_index_zval(event_enums, &enum_case); } if (events & PHP_POLL_HUP) { - ZVAL_OBJ(&enum_case, zend_enum_get_case_cstr(php_io_poll_event_class_entry, "HangUp")); - GC_ADDREF(Z_OBJ(enum_case)); + ZVAL_OBJ_COPY(&enum_case, zend_enum_get_case_by_id(php_io_poll_event_class_entry, ZEND_ENUM_Io_Poll_Event_HangUp)); add_next_index_zval(event_enums, &enum_case); } if (events & PHP_POLL_RDHUP) { - ZVAL_OBJ(&enum_case, zend_enum_get_case_cstr(php_io_poll_event_class_entry, "ReadHangUp")); - GC_ADDREF(Z_OBJ(enum_case)); + ZVAL_OBJ_COPY(&enum_case, zend_enum_get_case_by_id(php_io_poll_event_class_entry, ZEND_ENUM_Io_Poll_Event_ReadHangUp)); add_next_index_zval(event_enums, &enum_case); } if (events & PHP_POLL_ONESHOT) { - ZVAL_OBJ(&enum_case, zend_enum_get_case_cstr(php_io_poll_event_class_entry, "OneShot")); - GC_ADDREF(Z_OBJ(enum_case)); + ZVAL_OBJ_COPY(&enum_case, zend_enum_get_case_by_id(php_io_poll_event_class_entry, ZEND_ENUM_Io_Poll_Event_OneShot)); add_next_index_zval(event_enums, &enum_case); } if (events & PHP_POLL_ET) { - ZVAL_OBJ(&enum_case, zend_enum_get_case_cstr(php_io_poll_event_class_entry, "EdgeTriggered")); - GC_ADDREF(Z_OBJ(enum_case)); + ZVAL_OBJ_COPY(&enum_case, zend_enum_get_case_by_id(php_io_poll_event_class_entry, ZEND_ENUM_Io_Poll_Event_EdgeTriggered)); add_next_index_zval(event_enums, &enum_case); } diff --git a/ext/uri/uri_parser_rfc3986.c b/ext/uri/uri_parser_rfc3986.c index 123f244a51d7..b8a14a31c10e 100644 --- a/ext/uri/uri_parser_rfc3986.c +++ b/ext/uri/uri_parser_rfc3986.c @@ -125,19 +125,19 @@ ZEND_ATTRIBUTE_NONNULL void php_uri_parser_rfc3986_uri_type_read(php_uri_parser_ { const UriUriA *uriparser_uri = get_uri_for_reading(uri, PHP_URI_COMPONENT_READ_MODE_RAW); - const char *type; + zend_object *value; if (has_text_range(&uriparser_uri->scheme)) { - type = "Uri"; + value = zend_enum_get_case_by_id(php_uri_ce_rfc3986_uri_type, ZEND_ENUM_Uri_Rfc3986_UriType_Uri); } else if (has_text_range(&uriparser_uri->hostText)) { - type = "NetworkPathReference"; + value = zend_enum_get_case_by_id(php_uri_ce_rfc3986_uri_type, ZEND_ENUM_Uri_Rfc3986_UriType_NetworkPathReference); } else if (uriparser_uri->absolutePath) { - type = "AbsolutePathReference"; + value = zend_enum_get_case_by_id(php_uri_ce_rfc3986_uri_type, ZEND_ENUM_Uri_Rfc3986_UriType_AbsolutePathReference); } else { - type = "RelativePathReference"; + value = zend_enum_get_case_by_id(php_uri_ce_rfc3986_uri_type, ZEND_ENUM_Uri_Rfc3986_UriType_RelativePathReference); } - ZVAL_OBJ_COPY(retval, zend_enum_get_case_cstr(php_uri_ce_rfc3986_uri_type, type)); + ZVAL_OBJ_COPY(retval, value); } ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_scheme_read(void *uri, const php_uri_component_read_mode read_mode, zval *retval) @@ -290,19 +290,19 @@ ZEND_ATTRIBUTE_NONNULL void php_uri_parser_rfc3986_host_type_read(php_uri_parser return; } - const char *type; + zend_object *value; if (uriparser_uri->hostData.ip4 != NULL) { - type = "IPv4"; + value = zend_enum_get_case_by_id(php_uri_ce_rfc3986_uri_host_type, ZEND_ENUM_Uri_Rfc3986_UriHostType_IPv4); } else if (uriparser_uri->hostData.ip6 != NULL) { - type = "IPv6"; + value = zend_enum_get_case_by_id(php_uri_ce_rfc3986_uri_host_type, ZEND_ENUM_Uri_Rfc3986_UriHostType_IPv6); } else if (has_text_range(&uriparser_uri->hostData.ipFuture)) { - type = "IPvFuture"; + value = zend_enum_get_case_by_id(php_uri_ce_rfc3986_uri_host_type, ZEND_ENUM_Uri_Rfc3986_UriHostType_IPvFuture); } else { - type = "RegisteredName"; + value = zend_enum_get_case_by_id(php_uri_ce_rfc3986_uri_host_type, ZEND_ENUM_Uri_Rfc3986_UriHostType_RegisteredName); } - ZVAL_OBJ_COPY(retval, zend_enum_get_case_cstr(php_uri_ce_rfc3986_uri_host_type, type)); + ZVAL_OBJ_COPY(retval, value); } static zend_result php_uri_parser_rfc3986_host_write(void *uri, const zval *value, zval *errors) diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index 8cb3fe6cba01..d1875c4946de 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -39,6 +39,7 @@ #include "zend_mm_custom_handlers.h" #include "ext/uri/php_uri.h" #include "zend_observer.h" +#include "test_decl.h" #if defined(HAVE_LIBXML) && !defined(PHP_WIN32) # include @@ -622,7 +623,7 @@ static ZEND_FUNCTION(zend_get_unit_enum) { ZEND_PARSE_PARAMETERS_NONE(); - RETURN_OBJ_COPY(zend_enum_get_case_cstr(zend_test_unit_enum, "Foo")); + RETURN_OBJ_COPY(zend_enum_get_case_by_id(zend_test_unit_enum, ZEND_ENUM_ZendTestUnitEnum_Foo)); } static ZEND_FUNCTION(zend_test_zend_ini_parse_quantity) diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index 72f7428594c3..87de69c35c0b 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -45,6 +45,7 @@ static void php_stream_error_create_object(zval *zv, php_stream_error_entry *ent case_name = "Generic"; } + /* TODO: migrate to zend_enum_get_case_by_id() */ zend_object *enum_obj = zend_enum_get_case_cstr(php_ce_stream_error_code, case_name); ZEND_ASSERT(enum_obj != NULL);