summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2021-02-25 12:16:22 +0300
committerDmitry Stogov <dmitry@zend.com>2021-02-25 12:16:22 +0300
commit0f6c00200b95231bef00b9dfd94f35db924a3cc6 (patch)
tree76adb06c9c6c1383628cd094f85dc293632f6cc2
parent7920c9dd44e7daf11b28e5758f4dfe9b0f60f1d9 (diff)
downloadphp-git-0f6c00200b95231bef00b9dfd94f35db924a3cc6.tar.gz
Speed up __sleep() and __wakeup() calls
-rw-r--r--Zend/zend_string.h2
-rw-r--r--ext/standard/var.c63
-rw-r--r--ext/standard/var_unserializer.re28
3 files changed, 58 insertions, 35 deletions
diff --git a/Zend/zend_string.h b/Zend/zend_string.h
index c7580d63a4..88a2fddfb3 100644
--- a/Zend/zend_string.h
+++ b/Zend/zend_string.h
@@ -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 {
diff --git a/ext/standard/var.c b/ext/standard/var.c
index 5c13846a82..11a0873e8f 100644
--- a/ext/standard/var.c
+++ b/ext/standard/var.c
@@ -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);
diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re
index fb1ab2f496..a14e34125d 100644
--- a/ext/standard/var_unserializer.re
+++ b/ext/standard/var_unserializer.re
@@ -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))) {