]> granicus.if.org Git - php/commitdiff
Speed up __sleep() and __wakeup() calls
authorDmitry Stogov <dmitry@zend.com>
Thu, 25 Feb 2021 09:16:22 +0000 (12:16 +0300)
committerDmitry Stogov <dmitry@zend.com>
Thu, 25 Feb 2021 09:16:22 +0000 (12:16 +0300)
Zend/zend_string.h
ext/standard/var.c
ext/standard/var_unserializer.re

index c7580d63a4214af697f0d2e8661dc12d21edeb0a..88a2fddfb3f9b5ce1acf5455212f060190ac5b65 100644 (file)
@@ -551,6 +551,8 @@ EMPTY_SWITCH_DEFAULT_CASE()
        _(ZEND_STR_FALSE,                  "false") \
        _(ZEND_STR_NULL_LOWERCASE,         "null") \
        _(ZEND_STR_MIXED,                  "mixed") \
+       _(ZEND_STR_SLEEP,                  "__sleep") \
+       _(ZEND_STR_WAKEUP,                 "__wakeup") \
 
 
 typedef enum _zend_known_string_id {
index 5c13846a82ae215ee6dedfd57a255f95f00a9d82..11a0873e8fe1ec8930f0b19e1fd80ac659572527 100644 (file)
@@ -722,16 +722,27 @@ static inline bool php_var_serialize_class_name(smart_str *buf, zval *struc) /*
 }
 /* }}} */
 
-static int php_var_serialize_call_sleep(zval *retval, zval *struc) /* {{{ */
+static zend_result php_var_serialize_call_sleep(zend_object *obj, zend_function *fn, zval *retval) /* {{{ */
 {
-       zval fname;
-       int res;
+       zend_result res;
+       zend_fcall_info fci;
+       zend_fcall_info_cache fci_cache;
+
+       fci.size = sizeof(fci);
+       fci.object = obj;
+       fci.retval = retval;
+       fci.param_count = 0;
+       fci.params = NULL;
+       fci.named_params = NULL;
+       ZVAL_UNDEF(&fci.function_name);
+
+       fci_cache.function_handler = fn;
+       fci_cache.object = obj;
+       fci_cache.called_scope = obj->ce;
 
-       ZVAL_STRINGL(&fname, "__sleep", sizeof("__sleep") - 1);
        BG(serialize_lock)++;
-       res = call_user_function(NULL, struc, &fname, retval, 0, 0);
+       res = zend_call_function(&fci, &fci_cache);
        BG(serialize_lock)--;
-       zval_ptr_dtor_str(&fname);
 
        if (res == FAILURE || Z_ISUNDEF_P(retval)) {
                zval_ptr_dtor(retval);
@@ -739,11 +750,8 @@ static int php_var_serialize_call_sleep(zval *retval, zval *struc) /* {{{ */
        }
 
        if (!HASH_OF(retval)) {
-               zend_class_entry *ce;
-               ZEND_ASSERT(Z_TYPE_P(struc) == IS_OBJECT);
-               ce = Z_OBJCE_P(struc);
                zval_ptr_dtor(retval);
-               php_error_docref(NULL, E_WARNING, "%s::__sleep() should return an array only containing the names of instance-variables to serialize", ZSTR_VAL(ce->name));
+               php_error_docref(NULL, E_WARNING, "%s::__sleep() should return an array only containing the names of instance-variables to serialize", ZSTR_VAL(obj->ce->name));
                return FAILURE;
        }
 
@@ -1067,25 +1075,28 @@ again:
                                        return;
                                }
 
-                               if (ce != PHP_IC_ENTRY && zend_hash_str_exists(&ce->function_table, "__sleep", sizeof("__sleep")-1)) {
-                                       zval retval, tmp;
-
-                                       ZVAL_OBJ_COPY(&tmp, Z_OBJ_P(struc));
-
-                                       if (php_var_serialize_call_sleep(&retval, &tmp) == FAILURE) {
-                                               if (!EG(exception)) {
-                                                       /* we should still add element even if it's not OK,
-                                                        * since we already wrote the length of the array before */
-                                                       smart_str_appendl(buf, "N;", 2);
+                               if (ce != PHP_IC_ENTRY) {
+                                       zval *zv = zend_hash_find_ex(&ce->function_table, ZSTR_KNOWN(ZEND_STR_SLEEP), 1);
+
+                                       if (zv) {
+                                               zval retval, tmp;
+
+                                               ZVAL_OBJ_COPY(&tmp, Z_OBJ_P(struc));
+                                               if (php_var_serialize_call_sleep(Z_OBJ(tmp), Z_FUNC_P(zv), &retval) == FAILURE) {
+                                                       if (!EG(exception)) {
+                                                               /* we should still add element even if it's not OK,
+                                                                * since we already wrote the length of the array before */
+                                                               smart_str_appendl(buf, "N;", 2);
+                                                       }
+                                                       OBJ_RELEASE(Z_OBJ(tmp));
+                                                       return;
                                                }
-                                               zval_ptr_dtor(&tmp);
+
+                                               php_var_serialize_class(buf, &tmp, &retval, var_hash);
+                                               zval_ptr_dtor(&retval);
+                                               OBJ_RELEASE(Z_OBJ(tmp));
                                                return;
                                        }
-
-                                       php_var_serialize_class(buf, &tmp, &retval, var_hash);
-                                       zval_ptr_dtor(&retval);
-                                       zval_ptr_dtor(&tmp);
-                                       return;
                                }
 
                                incomplete_class = php_var_serialize_class_name(buf, struc);
index fb1ab2f49667ccf5b2fc8010254a130cba8824ad..a14e34125da3b0000225f0e99396cbc62a648d21 100644 (file)
@@ -222,8 +222,6 @@ PHPAPI void var_destroy(php_unserialize_data_t *var_hashx)
        var_entries *var_hash = (*var_hashx)->entries.next;
        var_dtor_entries *var_dtor_hash = (*var_hashx)->first_dtor;
        bool delayed_call_failed = 0;
-       zval wakeup_name;
-       ZVAL_UNDEF(&wakeup_name);
 
 #if VAR_ENTRIES_DBG
        fprintf(stderr, "var_destroy( " ZEND_LONG_FMT ")\n", var_hash?var_hash->used_slots:-1L);
@@ -246,12 +244,26 @@ PHPAPI void var_destroy(php_unserialize_data_t *var_hashx)
                                /* Perform delayed __wakeup calls */
                                if (!delayed_call_failed) {
                                        zval retval;
-                                       if (Z_ISUNDEF(wakeup_name)) {
-                                               ZVAL_STRINGL(&wakeup_name, "__wakeup", sizeof("__wakeup") - 1);
-                                       }
+                                       zend_fcall_info fci;
+                                       zend_fcall_info_cache fci_cache;
+
+                                       ZEND_ASSERT(Z_TYPE_P(zv) == IS_OBJECT);
+
+                                       fci.size = sizeof(fci);
+                                       fci.object = Z_OBJ_P(zv);
+                                       fci.retval = &retval;
+                                       fci.param_count = 0;
+                                       fci.params = NULL;
+                                       fci.named_params = NULL;
+                                       ZVAL_UNDEF(&fci.function_name);
+
+                                       fci_cache.function_handler = zend_hash_find_ptr(
+                                               &fci.object->ce->function_table, ZSTR_KNOWN(ZEND_STR_WAKEUP));
+                                       fci_cache.object = fci.object;
+                                       fci_cache.called_scope = fci.object->ce;
 
                                        BG(serialize_lock)++;
-                                       if (call_user_function(NULL, zv, &wakeup_name, &retval, 0, 0) == FAILURE || Z_ISUNDEF(retval)) {
+                                       if (zend_call_function(&fci, &fci_cache) == FAILURE || Z_ISUNDEF(retval)) {
                                                delayed_call_failed = 1;
                                                GC_ADD_FLAGS(Z_OBJ_P(zv), IS_OBJ_DESTRUCTOR_CALLED);
                                        }
@@ -288,8 +300,6 @@ PHPAPI void var_destroy(php_unserialize_data_t *var_hashx)
                var_dtor_hash = next;
        }
 
-       zval_ptr_dtor_nogc(&wakeup_name);
-
        if ((*var_hashx)->ref_props) {
                zend_hash_destroy((*var_hashx)->ref_props);
                FREE_HASHTABLE((*var_hashx)->ref_props);
@@ -788,7 +798,7 @@ static inline int object_common(UNSERIALIZE_PARAMETER, zend_long elements, bool
        }
 
        has_wakeup = Z_OBJCE_P(rval) != PHP_IC_ENTRY
-               && zend_hash_str_exists(&Z_OBJCE_P(rval)->function_table, "__wakeup", sizeof("__wakeup")-1);
+               && zend_hash_exists(&Z_OBJCE_P(rval)->function_table, ZSTR_KNOWN(ZEND_STR_WAKEUP));
 
        ht = Z_OBJPROP_P(rval);
        if (elements >= (zend_long)(HT_MAX_SIZE - zend_hash_num_elements(ht))) {