summaryrefslogtreecommitdiff
path: root/ext/spl
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2018-07-12 14:04:14 +0300
committerDmitry Stogov <dmitry@zend.com>2018-07-12 14:04:14 +0300
commit7d4e18b05dc962e923236a8d3df81fb0b10b113d (patch)
tree5e5e4301a9dc721a9ae2aa53a3db6ecf08f8ddf2 /ext/spl
parent0834679e40555bb8936a096cd7deda3841239985 (diff)
downloadphp-git-7d4e18b05dc962e923236a8d3df81fb0b10b113d.tar.gz
Improved user iterator implementation to reduce zend_class_entry memory consumption and avoid race condition during resolving/caching of user iterator functions of internal classes in ZTS build.
Diffstat (limited to 'ext/spl')
-rw-r--r--ext/spl/spl_array.c22
-rw-r--r--ext/spl/spl_fixedarray.c22
-rw-r--r--ext/spl/spl_iterators.c42
-rw-r--r--ext/spl/spl_observer.c12
4 files changed, 47 insertions, 51 deletions
diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c
index 0ed5c55687..59ae0b8c89 100644
--- a/ext/spl/spl_array.c
+++ b/ext/spl/spl_array.c
@@ -245,19 +245,19 @@ static zend_object *spl_array_object_new_ex(zend_class_entry *class_type, zval *
/* Cache iterator functions if ArrayIterator or derived. Check current's */
/* cache since only current is always required */
if (intern->std.handlers == &spl_handler_ArrayIterator) {
- if (!class_type->iterator_funcs.zf_current) {
- class_type->iterator_funcs.zf_rewind = zend_hash_str_find_ptr(&class_type->function_table, "rewind", sizeof("rewind") - 1);
- class_type->iterator_funcs.zf_valid = zend_hash_str_find_ptr(&class_type->function_table, "valid", sizeof("valid") - 1);
- class_type->iterator_funcs.zf_key = zend_hash_str_find_ptr(&class_type->function_table, "key", sizeof("key") - 1);
- class_type->iterator_funcs.zf_current = zend_hash_str_find_ptr(&class_type->function_table, "current", sizeof("current") - 1);
- class_type->iterator_funcs.zf_next = zend_hash_str_find_ptr(&class_type->function_table, "next", sizeof("next") - 1);
+ if (!class_type->iterator_funcs_ptr->zf_current) {
+ class_type->iterator_funcs_ptr->zf_rewind = zend_hash_str_find_ptr(&class_type->function_table, "rewind", sizeof("rewind") - 1);
+ class_type->iterator_funcs_ptr->zf_valid = zend_hash_str_find_ptr(&class_type->function_table, "valid", sizeof("valid") - 1);
+ class_type->iterator_funcs_ptr->zf_key = zend_hash_str_find_ptr(&class_type->function_table, "key", sizeof("key") - 1);
+ class_type->iterator_funcs_ptr->zf_current = zend_hash_str_find_ptr(&class_type->function_table, "current", sizeof("current") - 1);
+ class_type->iterator_funcs_ptr->zf_next = zend_hash_str_find_ptr(&class_type->function_table, "next", sizeof("next") - 1);
}
if (inherited) {
- if (class_type->iterator_funcs.zf_rewind->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_REWIND;
- if (class_type->iterator_funcs.zf_valid->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_VALID;
- if (class_type->iterator_funcs.zf_key->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_KEY;
- if (class_type->iterator_funcs.zf_current->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_CURRENT;
- if (class_type->iterator_funcs.zf_next->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_NEXT;
+ if (class_type->iterator_funcs_ptr->zf_rewind->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_REWIND;
+ if (class_type->iterator_funcs_ptr->zf_valid->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_VALID;
+ if (class_type->iterator_funcs_ptr->zf_key->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_KEY;
+ if (class_type->iterator_funcs_ptr->zf_current->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_CURRENT;
+ if (class_type->iterator_funcs_ptr->zf_next->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_NEXT;
}
}
diff --git a/ext/spl/spl_fixedarray.c b/ext/spl/spl_fixedarray.c
index e906c233eb..f738b9b059 100644
--- a/ext/spl/spl_fixedarray.c
+++ b/ext/spl/spl_fixedarray.c
@@ -240,27 +240,27 @@ static zend_object *spl_fixedarray_object_new_ex(zend_class_entry *class_type, z
php_error_docref(NULL, E_COMPILE_ERROR, "Internal compiler error, Class is not child of SplFixedArray");
}
- if (!class_type->iterator_funcs.zf_current) {
- class_type->iterator_funcs.zf_rewind = zend_hash_str_find_ptr(&class_type->function_table, "rewind", sizeof("rewind") - 1);
- class_type->iterator_funcs.zf_valid = zend_hash_str_find_ptr(&class_type->function_table, "valid", sizeof("valid") - 1);
- class_type->iterator_funcs.zf_key = zend_hash_str_find_ptr(&class_type->function_table, "key", sizeof("key") - 1);
- class_type->iterator_funcs.zf_current = zend_hash_str_find_ptr(&class_type->function_table, "current", sizeof("current") - 1);
- class_type->iterator_funcs.zf_next = zend_hash_str_find_ptr(&class_type->function_table, "next", sizeof("next") - 1);
+ if (!class_type->iterator_funcs_ptr->zf_current) {
+ class_type->iterator_funcs_ptr->zf_rewind = zend_hash_str_find_ptr(&class_type->function_table, "rewind", sizeof("rewind") - 1);
+ class_type->iterator_funcs_ptr->zf_valid = zend_hash_str_find_ptr(&class_type->function_table, "valid", sizeof("valid") - 1);
+ class_type->iterator_funcs_ptr->zf_key = zend_hash_str_find_ptr(&class_type->function_table, "key", sizeof("key") - 1);
+ class_type->iterator_funcs_ptr->zf_current = zend_hash_str_find_ptr(&class_type->function_table, "current", sizeof("current") - 1);
+ class_type->iterator_funcs_ptr->zf_next = zend_hash_str_find_ptr(&class_type->function_table, "next", sizeof("next") - 1);
}
if (inherited) {
- if (class_type->iterator_funcs.zf_rewind->common.scope != parent) {
+ if (class_type->iterator_funcs_ptr->zf_rewind->common.scope != parent) {
intern->flags |= SPL_FIXEDARRAY_OVERLOADED_REWIND;
}
- if (class_type->iterator_funcs.zf_valid->common.scope != parent) {
+ if (class_type->iterator_funcs_ptr->zf_valid->common.scope != parent) {
intern->flags |= SPL_FIXEDARRAY_OVERLOADED_VALID;
}
- if (class_type->iterator_funcs.zf_key->common.scope != parent) {
+ if (class_type->iterator_funcs_ptr->zf_key->common.scope != parent) {
intern->flags |= SPL_FIXEDARRAY_OVERLOADED_KEY;
}
- if (class_type->iterator_funcs.zf_current->common.scope != parent) {
+ if (class_type->iterator_funcs_ptr->zf_current->common.scope != parent) {
intern->flags |= SPL_FIXEDARRAY_OVERLOADED_CURRENT;
}
- if (class_type->iterator_funcs.zf_next->common.scope != parent) {
+ if (class_type->iterator_funcs_ptr->zf_next->common.scope != parent) {
intern->flags |= SPL_FIXEDARRAY_OVERLOADED_NEXT;
}
diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c
index c9f88ad6d9..3361fc9c73 100644
--- a/ext/spl/spl_iterators.c
+++ b/ext/spl/spl_iterators.c
@@ -443,6 +443,16 @@ static void spl_recursive_it_rewind(zend_object_iterator *iter)
spl_recursive_it_rewind_ex(Z_SPLRECURSIVE_IT_P(&iter->data), &iter->data);
}
+static const zend_object_iterator_funcs spl_recursive_it_iterator_funcs = {
+ spl_recursive_it_dtor,
+ spl_recursive_it_valid,
+ spl_recursive_it_get_current_data,
+ spl_recursive_it_get_current_key,
+ spl_recursive_it_move_forward,
+ spl_recursive_it_rewind,
+ NULL
+};
+
static zend_object_iterator *spl_recursive_it_get_iterator(zend_class_entry *ce, zval *zobject, int by_ref)
{
spl_recursive_it_iterator *iterator;
@@ -462,20 +472,10 @@ static zend_object_iterator *spl_recursive_it_get_iterator(zend_class_entry *ce,
zend_iterator_init((zend_object_iterator*)iterator);
ZVAL_COPY(&iterator->intern.data, zobject);
- iterator->intern.funcs = ce->iterator_funcs.funcs;
+ iterator->intern.funcs = &spl_recursive_it_iterator_funcs;
return (zend_object_iterator*)iterator;
}
-static const zend_object_iterator_funcs spl_recursive_it_iterator_funcs = {
- spl_recursive_it_dtor,
- spl_recursive_it_valid,
- spl_recursive_it_get_current_data,
- spl_recursive_it_get_current_key,
- spl_recursive_it_move_forward,
- spl_recursive_it_rewind,
- NULL
-};
-
static void spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *ce_base, zend_class_entry *ce_inner, recursive_it_it_type rit_type)
{
zval *object = getThis();
@@ -496,7 +496,7 @@ static void spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_cla
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "o|lzl", &iterator, &flags, &user_caching_it_flags, &mode) == SUCCESS) {
if (instanceof_function(Z_OBJCE_P(iterator), zend_ce_aggregate)) {
- zend_call_method_with_0_params(iterator, Z_OBJCE_P(iterator), &Z_OBJCE_P(iterator)->iterator_funcs.zf_new_iterator, "getiterator", &aggregate_retval);
+ zend_call_method_with_0_params(iterator, Z_OBJCE_P(iterator), &Z_OBJCE_P(iterator)->iterator_funcs_ptr->zf_new_iterator, "getiterator", &aggregate_retval);
iterator = &aggregate_retval;
} else {
Z_ADDREF_P(iterator);
@@ -524,7 +524,7 @@ static void spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_cla
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "o|ll", &iterator, &mode, &flags) == SUCCESS) {
if (instanceof_function(Z_OBJCE_P(iterator), zend_ce_aggregate)) {
- zend_call_method_with_0_params(iterator, Z_OBJCE_P(iterator), &Z_OBJCE_P(iterator)->iterator_funcs.zf_new_iterator, "getiterator", &aggregate_retval);
+ zend_call_method_with_0_params(iterator, Z_OBJCE_P(iterator), &Z_OBJCE_P(iterator)->iterator_funcs_ptr->zf_new_iterator, "getiterator", &aggregate_retval);
iterator = &aggregate_retval;
} else {
Z_ADDREF_P(iterator);
@@ -1353,14 +1353,11 @@ static const zend_function_entry spl_funcs_RecursiveTreeIterator[] = {
#if MBO_0
static int spl_dual_it_gets_implemented(zend_class_entry *interface, zend_class_entry *class_type)
{
- class_type->iterator_funcs.zf_valid = NULL;
- class_type->iterator_funcs.zf_current = NULL;
- class_type->iterator_funcs.zf_key = NULL;
- class_type->iterator_funcs.zf_next = NULL;
- class_type->iterator_funcs.zf_rewind = NULL;
- if (!class_type->iterator_funcs.funcs) {
- class_type->iterator_funcs.funcs = &zend_interface_iterator_funcs_iterator;
- }
+ class_type->iterator_funcs_ptr->zf_valid = NULL;
+ class_type->iterator_funcs_ptr->zf_current = NULL;
+ class_type->iterator_funcs_ptr->zf_key = NULL;
+ class_type->iterator_funcs_ptr->zf_next = NULL;
+ class_type->iterator_funcs_ptr->zf_rewind = NULL;
return SUCCESS;
}
@@ -1518,7 +1515,7 @@ static spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, z
ce = ce_cast;
}
if (instanceof_function(ce, zend_ce_aggregate)) {
- zend_call_method_with_0_params(zobject, ce, &ce->iterator_funcs.zf_new_iterator, "getiterator", &retval);
+ zend_call_method_with_0_params(zobject, ce, &ce->iterator_funcs_ptr->zf_new_iterator, "getiterator", &retval);
if (EG(exception)) {
zval_ptr_dtor(&retval);
return NULL;
@@ -3712,7 +3709,6 @@ PHP_MINIT_FUNCTION(spl_iterators)
spl_handlers_dual_it.free_obj = spl_dual_it_free_storage;
spl_ce_RecursiveIteratorIterator->get_iterator = spl_recursive_it_get_iterator;
- spl_ce_RecursiveIteratorIterator->iterator_funcs.funcs = &spl_recursive_it_iterator_funcs;
REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "LEAVES_ONLY", RIT_LEAVES_ONLY);
REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "SELF_FIRST", RIT_SELF_FIRST);
diff --git a/ext/spl/spl_observer.c b/ext/spl/spl_observer.c
index dde06d288b..0d99f066fc 100644
--- a/ext/spl/spl_observer.c
+++ b/ext/spl/spl_observer.c
@@ -1031,7 +1031,7 @@ SPL_METHOD(MultipleIterator, rewind)
zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
while ((element = zend_hash_get_current_data_ptr_ex(&intern->storage, &intern->pos)) != NULL && !EG(exception)) {
it = &element->obj;
- zend_call_method_with_0_params(it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_rewind, "rewind", NULL);
+ zend_call_method_with_0_params(it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs_ptr->zf_rewind, "rewind", NULL);
zend_hash_move_forward_ex(&intern->storage, &intern->pos);
}
}
@@ -1054,7 +1054,7 @@ SPL_METHOD(MultipleIterator, next)
zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
while ((element = zend_hash_get_current_data_ptr_ex(&intern->storage, &intern->pos)) != NULL && !EG(exception)) {
it = &element->obj;
- zend_call_method_with_0_params(it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_next, "next", NULL);
+ zend_call_method_with_0_params(it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs_ptr->zf_next, "next", NULL);
zend_hash_move_forward_ex(&intern->storage, &intern->pos);
}
}
@@ -1084,7 +1084,7 @@ SPL_METHOD(MultipleIterator, valid)
zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
while ((element = zend_hash_get_current_data_ptr_ex(&intern->storage, &intern->pos)) != NULL && !EG(exception)) {
it = &element->obj;
- zend_call_method_with_0_params(it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_valid, "valid", &retval);
+ zend_call_method_with_0_params(it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs_ptr->zf_valid, "valid", &retval);
if (!Z_ISUNDEF(retval)) {
valid = (Z_TYPE(retval) == IS_TRUE);
@@ -1120,7 +1120,7 @@ static void spl_multiple_iterator_get_all(spl_SplObjectStorage *intern, int get_
zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
while ((element = zend_hash_get_current_data_ptr_ex(&intern->storage, &intern->pos)) != NULL && !EG(exception)) {
it = &element->obj;
- zend_call_method_with_0_params(it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_valid, "valid", &retval);
+ zend_call_method_with_0_params(it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs_ptr->zf_valid, "valid", &retval);
if (!Z_ISUNDEF(retval)) {
valid = Z_TYPE(retval) == IS_TRUE;
@@ -1131,9 +1131,9 @@ static void spl_multiple_iterator_get_all(spl_SplObjectStorage *intern, int get_
if (valid) {
if (SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT == get_type) {
- zend_call_method_with_0_params(it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_current, "current", &retval);
+ zend_call_method_with_0_params(it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs_ptr->zf_current, "current", &retval);
} else {
- zend_call_method_with_0_params(it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_key, "key", &retval);
+ zend_call_method_with_0_params(it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs_ptr->zf_key, "key", &retval);
}
if (Z_ISUNDEF(retval)) {
zend_throw_exception(spl_ce_RuntimeException, "Failed to call sub iterator method", 0);