From 2740c64b023efec79a542e5a975b32a4d950dcfb Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Wed, 28 Aug 2024 23:35:36 +0200 Subject: [PATCH] Optimize DOM property access MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For the read and write implementation, store the handler pointer in the first cache slot. For the write implementation, use the second cache slot to store the property info. For a micro-benchmark that performs a write: ```php $dom = new DOMDocument; for ($i=0;$i<9999999;$i++) $dom->strictErrorChecking = false; ``` I obtain the following results on an i7-4790: ``` ./sapi/cli/php ./write.php ran 1.42 ± 0.08 times faster than ./sapi/cli/php_old ./write.php ``` For a micro-benchmark that performs a read: ```php $dom = new DOMDocument; for ($i=0;$i<9999999;$i++) $dom->strictErrorChecking; ``` I obtain the following results on the same machine: ``` ./sapi/cli/php ./read.php ran 1.29 ± 0.13 times faster than ./sapi/cli/php_old ./read.php ``` --- ext/dom/php_dom.c | 45 +++++++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/ext/dom/php_dom.c b/ext/dom/php_dom.c index e69a2cd20564e..42a6876b414b6 100644 --- a/ext/dom/php_dom.c +++ b/ext/dom/php_dom.c @@ -365,16 +365,31 @@ static zval *dom_get_property_ptr_ptr(zend_object *object, zend_string *name, in return NULL; } +static zend_always_inline const dom_prop_handler *dom_get_prop_handler(const dom_object *obj, zend_string *name, void **cache_slot) +{ + const dom_prop_handler *hnd = NULL; + + if (obj->prop_handler != NULL) { + if (cache_slot) { + hnd = *cache_slot; + } + if (!hnd) { + hnd = zend_hash_find_ptr(obj->prop_handler, name); + if (cache_slot) { + *cache_slot = (void *) hnd; + } + } + } + + return hnd; +} + /* {{{ dom_read_property */ zval *dom_read_property(zend_object *object, zend_string *name, int type, void **cache_slot, zval *rv) { dom_object *obj = php_dom_obj_from_obj(object); zval *retval; - dom_prop_handler *hnd = NULL; - - if (obj->prop_handler != NULL) { - hnd = zend_hash_find_ptr(obj->prop_handler, name); - } + const dom_prop_handler *hnd = dom_get_prop_handler(obj, name, cache_slot); if (hnd) { int ret = hnd->read_func(obj, rv); @@ -394,19 +409,25 @@ zval *dom_read_property(zend_object *object, zend_string *name, int type, void * zval *dom_write_property(zend_object *object, zend_string *name, zval *value, void **cache_slot) { dom_object *obj = php_dom_obj_from_obj(object); - dom_prop_handler *hnd = NULL; - - if (obj->prop_handler != NULL) { - hnd = zend_hash_find_ptr(obj->prop_handler, name); - } + const dom_prop_handler *hnd = dom_get_prop_handler(obj, name, cache_slot); if (hnd) { - if (!hnd->write_func) { + if (UNEXPECTED(!hnd->write_func)) { zend_readonly_property_modification_error_ex(ZSTR_VAL(object->ce->name), ZSTR_VAL(name)); return &EG(error_zval); } - zend_property_info *prop = zend_get_property_info(object->ce, name, /* silent */ true); + zend_property_info *prop = NULL; + if (cache_slot) { + prop = *(cache_slot + 1); + } + if (!prop) { + prop = zend_get_property_info(object->ce, name, /* silent */ true); + if (cache_slot) { + *(cache_slot + 1) = prop; + } + } + ZEND_ASSERT(prop && ZEND_TYPE_IS_SET(prop->type)); zval tmp; ZVAL_COPY(&tmp, value);