Merge branch 'immutable' into preload

* immutable:
  Reverted back ce->iterator_funcs_ptr. Initialize ce->iterator_funcs_ptr fields in immutable classes.
This commit is contained in:
Dmitry Stogov 2018-10-17 14:14:23 +03:00
commit d33908a99a
15 changed files with 125 additions and 192 deletions

View file

@ -128,9 +128,9 @@ PHP 7.4 INTERNALS UPGRADE NOTES
Few related data structures were changed to allow addressing mutable data Few related data structures were changed to allow addressing mutable data
structures from immutable ones. This access is implemented through structures from immutable ones. This access is implemented through
ZEND_MAP_PTR... abstraction macros and, basically, uses additional level of ZEND_MAP_PTR... abstraction macros and, basically, uses additional level of
indirection. op_array->run_time_cache, op_array->static_variables_ptr, indirection. op_array->run_time_cache, op_array->static_variables_ptr and
class_entry->static_members_table and class_entry->iterator_funcs_ptr now class_entry->static_members_table now have to be accessed through
have to be accessed through ZEND_MAP_PTR... macros. ZEND_MAP_PTR... macros.
It's also not allowed to change op_array->reserved[] handles of immutable It's also not allowed to change op_array->reserved[] handles of immutable
op_arrays. Instead, now you have to reserve op_array handle using op_arrays. Instead, now you have to reserve op_array handle using
zend_get_op_array_extension_handle() during MINIT and access its value zend_get_op_array_extension_handle() during MINIT and access its value

View file

@ -148,7 +148,7 @@ struct _zend_class_entry {
zend_function *unserialize_func; zend_function *unserialize_func;
/* allocated only if class implements Iterator or IteratorAggregate interface */ /* allocated only if class implements Iterator or IteratorAggregate interface */
ZEND_MAP_PTR_DEF(zend_class_iterator_funcs *, iterator_funcs_ptr); zend_class_iterator_funcs *iterator_funcs_ptr;
/* handlers */ /* handlers */
union { union {

View file

@ -219,7 +219,7 @@ typedef struct _zend_fcall_info_cache {
class_container.trait_precedences = NULL; \ class_container.trait_precedences = NULL; \
class_container.interfaces = NULL; \ class_container.interfaces = NULL; \
class_container.get_iterator = NULL; \ class_container.get_iterator = NULL; \
ZEND_MAP_PTR_INIT(class_container.iterator_funcs_ptr, NULL); \ class_container.iterator_funcs_ptr = NULL; \
class_container.info.internal.module = NULL; \ class_container.info.internal.module = NULL; \
class_container.info.internal.builtin_functions = functions; \ class_container.info.internal.builtin_functions = functions; \
} }

View file

@ -1638,7 +1638,7 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify
ce->__tostring = NULL; ce->__tostring = NULL;
ce->create_object = NULL; ce->create_object = NULL;
ce->get_iterator = NULL; ce->get_iterator = NULL;
ZEND_MAP_PTR_INIT(ce->iterator_funcs_ptr, NULL); ce->iterator_funcs_ptr = NULL;
ce->get_static_method = NULL; ce->get_static_method = NULL;
ce->parent = NULL; ce->parent = NULL;
ce->parent_name = NULL; ce->parent_name = NULL;

View file

@ -92,9 +92,9 @@ static void do_inherit_parent_constructor(zend_class_entry *ce) /* {{{ */
if (EXPECTED(!ce->get_iterator)) { if (EXPECTED(!ce->get_iterator)) {
ce->get_iterator = parent->get_iterator; ce->get_iterator = parent->get_iterator;
} }
if (ZEND_MAP_PTR(parent->iterator_funcs_ptr)) { if (parent->iterator_funcs_ptr) {
/* Must be initialized through iface->interface_gets_implemented() */ /* Must be initialized through iface->interface_gets_implemented() */
ZEND_ASSERT(ZEND_MAP_PTR_GET(ce->iterator_funcs_ptr)); ZEND_ASSERT(ce->iterator_funcs_ptr);
} }
if (EXPECTED(!ce->__get)) { if (EXPECTED(!ce->__get)) {
ce->__get = parent->__get; ce->__get = parent->__get;

View file

@ -119,36 +119,12 @@ ZEND_API zval* zend_call_method(zval *object, zend_class_entry *obj_ce, zend_fun
} }
/* }}} */ /* }}} */
typedef struct _zend_class_iterator_funcs_ptr {
zend_class_iterator_funcs *ptr;
zend_class_iterator_funcs data;
} zend_class_iterator_funcs_ptr;
/* iterator interface, c-level functions used by engine */ /* iterator interface, c-level functions used by engine */
static zend_never_inline zend_class_iterator_funcs* zend_alloc_iterator_funcs_ptr(zend_class_entry *ce) /* {{{ */
{
zend_class_iterator_funcs *ptr = zend_arena_alloc(&CG(arena), sizeof(zend_class_iterator_funcs));
memset(ptr, 0, sizeof(zend_class_iterator_funcs));
ZEND_MAP_PTR_SET(ce->iterator_funcs_ptr, ptr);
return ptr;
}
/* }}} */
static zend_always_inline zend_class_iterator_funcs* zend_get_iterator_funcs_ptr(zend_class_entry *ce) /* {{{ */
{
if (ZEND_MAP_PTR_GET(ce->iterator_funcs_ptr)) {
return ZEND_MAP_PTR_GET(ce->iterator_funcs_ptr);
} else {
return zend_alloc_iterator_funcs_ptr(ce);
}
}
/* }}} */
/* {{{ zend_user_it_new_iterator */ /* {{{ zend_user_it_new_iterator */
ZEND_API void zend_user_it_new_iterator(zend_class_entry *ce, zval *object, zval *retval) ZEND_API void zend_user_it_new_iterator(zend_class_entry *ce, zval *object, zval *retval)
{ {
zend_class_iterator_funcs *iterator_funcs_ptr = zend_get_iterator_funcs_ptr(ce); zend_call_method_with_0_params(object, ce, &ce->iterator_funcs_ptr->zf_new_iterator, "getiterator", retval);
zend_call_method_with_0_params(object, ce, &iterator_funcs_ptr->zf_new_iterator, "getiterator", retval);
} }
/* }}} */ /* }}} */
@ -183,10 +159,8 @@ ZEND_API int zend_user_it_valid(zend_object_iterator *_iter)
zval *object = &iter->it.data; zval *object = &iter->it.data;
zval more; zval more;
int result; int result;
zend_class_entry *ce = iter->ce;
zend_class_iterator_funcs *iterator_funcs_ptr = zend_get_iterator_funcs_ptr(ce);
zend_call_method_with_0_params(object, ce, &iterator_funcs_ptr->zf_valid, "valid", &more); zend_call_method_with_0_params(object, iter->ce, &iter->ce->iterator_funcs_ptr->zf_valid, "valid", &more);
result = i_zend_is_true(&more); result = i_zend_is_true(&more);
zval_ptr_dtor(&more); zval_ptr_dtor(&more);
return result ? SUCCESS : FAILURE; return result ? SUCCESS : FAILURE;
@ -202,10 +176,7 @@ ZEND_API zval *zend_user_it_get_current_data(zend_object_iterator *_iter)
zval *object = &iter->it.data; zval *object = &iter->it.data;
if (Z_ISUNDEF(iter->value)) { if (Z_ISUNDEF(iter->value)) {
zend_class_entry *ce = iter->ce; zend_call_method_with_0_params(object, iter->ce, &iter->ce->iterator_funcs_ptr->zf_current, "current", &iter->value);
zend_class_iterator_funcs *iterator_funcs_ptr = zend_get_iterator_funcs_ptr(ce);
zend_call_method_with_0_params(object, ce, &iterator_funcs_ptr->zf_current, "current", &iter->value);
} }
return &iter->value; return &iter->value;
} }
@ -217,10 +188,8 @@ ZEND_API void zend_user_it_get_current_key(zend_object_iterator *_iter, zval *ke
zend_user_iterator *iter = (zend_user_iterator*)_iter; zend_user_iterator *iter = (zend_user_iterator*)_iter;
zval *object = &iter->it.data; zval *object = &iter->it.data;
zval retval; zval retval;
zend_class_entry *ce = iter->ce;
zend_class_iterator_funcs *iterator_funcs_ptr = zend_get_iterator_funcs_ptr(ce);
zend_call_method_with_0_params(object, ce, &iterator_funcs_ptr->zf_key, "key", &retval); zend_call_method_with_0_params(object, iter->ce, &iter->ce->iterator_funcs_ptr->zf_key, "key", &retval);
if (Z_TYPE(retval) != IS_UNDEF) { if (Z_TYPE(retval) != IS_UNDEF) {
ZVAL_ZVAL(key, &retval, 1, 1); ZVAL_ZVAL(key, &retval, 1, 1);
@ -239,11 +208,9 @@ ZEND_API void zend_user_it_move_forward(zend_object_iterator *_iter)
{ {
zend_user_iterator *iter = (zend_user_iterator*)_iter; zend_user_iterator *iter = (zend_user_iterator*)_iter;
zval *object = &iter->it.data; zval *object = &iter->it.data;
zend_class_entry *ce = iter->ce;
zend_class_iterator_funcs *iterator_funcs_ptr = zend_get_iterator_funcs_ptr(ce);
zend_user_it_invalidate_current(_iter); zend_user_it_invalidate_current(_iter);
zend_call_method_with_0_params(object, ce, &iterator_funcs_ptr->zf_next, "next", NULL); zend_call_method_with_0_params(object, iter->ce, &iter->ce->iterator_funcs_ptr->zf_next, "next", NULL);
} }
/* }}} */ /* }}} */
@ -252,11 +219,9 @@ ZEND_API void zend_user_it_rewind(zend_object_iterator *_iter)
{ {
zend_user_iterator *iter = (zend_user_iterator*)_iter; zend_user_iterator *iter = (zend_user_iterator*)_iter;
zval *object = &iter->it.data; zval *object = &iter->it.data;
zend_class_entry *ce = iter->ce;
zend_class_iterator_funcs *iterator_funcs_ptr = zend_get_iterator_funcs_ptr(ce);
zend_user_it_invalidate_current(_iter); zend_user_it_invalidate_current(_iter);
zend_call_method_with_0_params(object, ce, &iterator_funcs_ptr->zf_rewind, "rewind", NULL); zend_call_method_with_0_params(object, iter->ce, &iter->ce->iterator_funcs_ptr->zf_rewind, "rewind", NULL);
} }
/* }}} */ /* }}} */
@ -347,7 +312,6 @@ static int zend_implement_aggregate(zend_class_entry *interface, zend_class_entr
{ {
uint32_t i; uint32_t i;
int t = -1; int t = -1;
zend_class_iterator_funcs *iterator_funcs_ptr;
if (class_type->get_iterator) { if (class_type->get_iterator) {
if (class_type->type == ZEND_INTERNAL_CLASS) { if (class_type->type == ZEND_INTERNAL_CLASS) {
@ -376,31 +340,17 @@ static int zend_implement_aggregate(zend_class_entry *interface, zend_class_entr
} }
} }
class_type->get_iterator = zend_user_it_get_new_iterator; class_type->get_iterator = zend_user_it_get_new_iterator;
if (ZEND_MAP_PTR(class_type->iterator_funcs_ptr)) { if (class_type->iterator_funcs_ptr != NULL) {
iterator_funcs_ptr = ZEND_MAP_PTR_GET(class_type->iterator_funcs_ptr); class_type->iterator_funcs_ptr->zf_new_iterator = NULL;
ZEND_ASSERT(iterator_funcs_ptr);
if (class_type->type == ZEND_USER_CLASS) {
iterator_funcs_ptr->zf_new_iterator = NULL;
return SUCCESS;
}
} else if (class_type->type == ZEND_INTERNAL_CLASS) { } else if (class_type->type == ZEND_INTERNAL_CLASS) {
/* We can use pointer even in ZTS mode, because this structure is read-only */ class_type->iterator_funcs_ptr = calloc(1, sizeof(zend_class_iterator_funcs));
zend_class_iterator_funcs_ptr *iterator_funcs_ptr_ptr =
calloc(1, sizeof(zend_class_iterator_funcs_ptr));
ZEND_MAP_PTR_INIT(class_type->iterator_funcs_ptr, &iterator_funcs_ptr_ptr->ptr);
iterator_funcs_ptr = &iterator_funcs_ptr_ptr->data;
iterator_funcs_ptr_ptr->ptr = iterator_funcs_ptr;
} else { } else {
zend_class_iterator_funcs_ptr *iterator_funcs_ptr_ptr = class_type->iterator_funcs_ptr = zend_arena_alloc(&CG(arena), sizeof(zend_class_iterator_funcs));
zend_arena_alloc(&CG(arena), sizeof(zend_class_iterator_funcs_ptr)); memset(class_type->iterator_funcs_ptr, 0, sizeof(zend_class_iterator_funcs));
iterator_funcs_ptr_ptr->ptr = &iterator_funcs_ptr_ptr->data; }
ZEND_MAP_PTR_INIT(class_type->iterator_funcs_ptr, &iterator_funcs_ptr_ptr->ptr); if (class_type->type == ZEND_INTERNAL_CLASS) {
iterator_funcs_ptr = &iterator_funcs_ptr_ptr->data; class_type->iterator_funcs_ptr->zf_new_iterator = zend_hash_str_find_ptr(&class_type->function_table, "getiterator", sizeof("getiterator") - 1);
iterator_funcs_ptr_ptr->ptr = iterator_funcs_ptr;
memset(iterator_funcs_ptr, 0, sizeof(zend_class_iterator_funcs));
return SUCCESS;
} }
iterator_funcs_ptr->zf_new_iterator = zend_hash_str_find_ptr(&class_type->function_table, "getiterator", sizeof("getiterator") - 1);
return SUCCESS; return SUCCESS;
} }
/* }}} */ /* }}} */
@ -408,8 +358,6 @@ static int zend_implement_aggregate(zend_class_entry *interface, zend_class_entr
/* {{{ zend_implement_iterator */ /* {{{ zend_implement_iterator */
static int zend_implement_iterator(zend_class_entry *interface, zend_class_entry *class_type) static int zend_implement_iterator(zend_class_entry *interface, zend_class_entry *class_type)
{ {
zend_class_iterator_funcs *iterator_funcs_ptr;
if (class_type->get_iterator && class_type->get_iterator != zend_user_it_get_iterator) { if (class_type->get_iterator && class_type->get_iterator != zend_user_it_get_iterator) {
if (class_type->type == ZEND_INTERNAL_CLASS) { if (class_type->type == ZEND_INTERNAL_CLASS) {
/* inheritance ensures the class has the necessary userland methods */ /* inheritance ensures the class has the necessary userland methods */
@ -426,39 +374,25 @@ static int zend_implement_iterator(zend_class_entry *interface, zend_class_entry
} }
} }
class_type->get_iterator = zend_user_it_get_iterator; class_type->get_iterator = zend_user_it_get_iterator;
if (ZEND_MAP_PTR(class_type->iterator_funcs_ptr)) { if (class_type->iterator_funcs_ptr != NULL) {
iterator_funcs_ptr = ZEND_MAP_PTR_GET(class_type->iterator_funcs_ptr); class_type->iterator_funcs_ptr->zf_valid = NULL;
ZEND_ASSERT(iterator_funcs_ptr); class_type->iterator_funcs_ptr->zf_current = NULL;
if (class_type->type == ZEND_USER_CLASS) { class_type->iterator_funcs_ptr->zf_key = NULL;
iterator_funcs_ptr->zf_valid = NULL; class_type->iterator_funcs_ptr->zf_next = NULL;
iterator_funcs_ptr->zf_current = NULL; class_type->iterator_funcs_ptr->zf_rewind = NULL;
iterator_funcs_ptr->zf_key = NULL;
iterator_funcs_ptr->zf_next = NULL;
iterator_funcs_ptr->zf_rewind = NULL;
return SUCCESS;
}
} else if (class_type->type == ZEND_INTERNAL_CLASS) { } else if (class_type->type == ZEND_INTERNAL_CLASS) {
/* We can use pointer even in ZTS mode, because this structure is read-only */ class_type->iterator_funcs_ptr = calloc(1, sizeof(zend_class_iterator_funcs));
zend_class_iterator_funcs_ptr *iterator_funcs_ptr_ptr =
calloc(1, sizeof(zend_class_iterator_funcs_ptr));
ZEND_MAP_PTR_INIT(class_type->iterator_funcs_ptr, &iterator_funcs_ptr_ptr->ptr);
iterator_funcs_ptr = &iterator_funcs_ptr_ptr->data;
iterator_funcs_ptr_ptr->ptr = iterator_funcs_ptr;
} else { } else {
zend_class_iterator_funcs_ptr *iterator_funcs_ptr_ptr = class_type->iterator_funcs_ptr = zend_arena_alloc(&CG(arena), sizeof(zend_class_iterator_funcs));
zend_arena_alloc(&CG(arena), sizeof(zend_class_iterator_funcs_ptr)); memset(class_type->iterator_funcs_ptr, 0, sizeof(zend_class_iterator_funcs));
iterator_funcs_ptr_ptr->ptr = &iterator_funcs_ptr_ptr->data; }
ZEND_MAP_PTR_INIT(class_type->iterator_funcs_ptr, &iterator_funcs_ptr_ptr->ptr); if (class_type->type == ZEND_INTERNAL_CLASS) {
iterator_funcs_ptr = &iterator_funcs_ptr_ptr->data; class_type->iterator_funcs_ptr->zf_rewind = zend_hash_str_find_ptr(&class_type->function_table, "rewind", sizeof("rewind") - 1);
iterator_funcs_ptr_ptr->ptr = iterator_funcs_ptr; class_type->iterator_funcs_ptr->zf_valid = zend_hash_str_find_ptr(&class_type->function_table, "valid", sizeof("valid") - 1);
memset(iterator_funcs_ptr, 0, sizeof(zend_class_iterator_funcs)); class_type->iterator_funcs_ptr->zf_key = zend_hash_str_find_ptr(&class_type->function_table, "key", sizeof("key") - 1);
return SUCCESS; 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);
} }
iterator_funcs_ptr->zf_rewind = zend_hash_str_find_ptr(&class_type->function_table, "rewind", sizeof("rewind") - 1);
iterator_funcs_ptr->zf_valid = zend_hash_str_find_ptr(&class_type->function_table, "valid", sizeof("valid") - 1);
iterator_funcs_ptr->zf_key = zend_hash_str_find_ptr(&class_type->function_table, "key", sizeof("key") - 1);
iterator_funcs_ptr->zf_current = zend_hash_str_find_ptr(&class_type->function_table, "current", sizeof("current") - 1);
iterator_funcs_ptr->zf_next = zend_hash_str_find_ptr(&class_type->function_table, "next", sizeof("next") - 1);
return SUCCESS; return SUCCESS;
} }
/* }}} */ /* }}} */

View file

@ -347,8 +347,8 @@ ZEND_API void destroy_zend_class(zval *zv)
} ZEND_HASH_FOREACH_END(); } ZEND_HASH_FOREACH_END();
zend_hash_destroy(&ce->constants_table); zend_hash_destroy(&ce->constants_table);
} }
if (ZEND_MAP_PTR(ce->iterator_funcs_ptr)) { if (ce->iterator_funcs_ptr) {
free(ZEND_MAP_PTR(ce->iterator_funcs_ptr)); free(ce->iterator_funcs_ptr);
} }
if (ce->num_interfaces > 0) { if (ce->num_interfaces > 0) {
free(ce->interfaces); free(ce->interfaces);

View file

@ -373,11 +373,6 @@ static void zend_class_copy_ctor(zend_class_entry **pce)
ce->trait_precedences = trait_precedences; ce->trait_precedences = trait_precedences;
} }
} }
if (ZEND_MAP_PTR(ce->iterator_funcs_ptr)) {
ZEND_MAP_PTR_INIT(ce->iterator_funcs_ptr, ARENA_REALLOC(ZEND_MAP_PTR(ce->iterator_funcs_ptr)));
ZEND_MAP_PTR_SET(ce->iterator_funcs_ptr, ARENA_REALLOC(ZEND_MAP_PTR_GET(ce->iterator_funcs_ptr)));
}
} }
static void zend_accel_function_hash_copy(HashTable *target, HashTable *source) static void zend_accel_function_hash_copy(HashTable *target, HashTable *source)

View file

@ -757,14 +757,17 @@ static void zend_file_cache_serialize_class(zval *zv,
SERIALIZE_PTR(ce->__callstatic); SERIALIZE_PTR(ce->__callstatic);
SERIALIZE_PTR(ce->__debugInfo); SERIALIZE_PTR(ce->__debugInfo);
ZEND_MAP_PTR_INIT(ce->static_members_table, &ce->default_static_members_table); if (ce->iterator_funcs_ptr) {
if (ZEND_MAP_PTR(ce->iterator_funcs_ptr)) { SERIALIZE_PTR(ce->iterator_funcs_ptr->zf_new_iterator);
if (ce->ce_flags & ZEND_ACC_IMMUTABLE) { SERIALIZE_PTR(ce->iterator_funcs_ptr->zf_rewind);
ZEND_MAP_PTR_INIT(ce->iterator_funcs_ptr, (void*)(uintptr_t)1); SERIALIZE_PTR(ce->iterator_funcs_ptr->zf_valid);
} else { SERIALIZE_PTR(ce->iterator_funcs_ptr->zf_key);
SERIALIZE_PTR(ZEND_MAP_PTR(ce->iterator_funcs_ptr)); SERIALIZE_PTR(ce->iterator_funcs_ptr->zf_current);
} SERIALIZE_PTR(ce->iterator_funcs_ptr->zf_next);
SERIALIZE_PTR(ce->iterator_funcs_ptr);
} }
ZEND_MAP_PTR_INIT(ce->static_members_table, &ce->default_static_members_table);
} }
static void zend_file_cache_serialize(zend_persistent_script *script, static void zend_file_cache_serialize(zend_persistent_script *script,
@ -1413,18 +1416,20 @@ static void zend_file_cache_unserialize_class(zval *zv,
ce->unserialize = zend_class_unserialize_deny; ce->unserialize = zend_class_unserialize_deny;
} }
if (ce->ce_flags & ZEND_ACC_IMMUTABLE) { if (ce->iterator_funcs_ptr) {
if (ce->default_static_members_table) { UNSERIALIZE_PTR(ce->iterator_funcs_ptr);
ZEND_MAP_PTR_NEW(ce->static_members_table); UNSERIALIZE_PTR(ce->iterator_funcs_ptr->zf_new_iterator);
} else { UNSERIALIZE_PTR(ce->iterator_funcs_ptr->zf_rewind);
ZEND_MAP_PTR_INIT(ce->static_members_table, &ce->default_static_members_table); UNSERIALIZE_PTR(ce->iterator_funcs_ptr->zf_valid);
} UNSERIALIZE_PTR(ce->iterator_funcs_ptr->zf_key);
if (ZEND_MAP_PTR(ce->iterator_funcs_ptr)) { UNSERIALIZE_PTR(ce->iterator_funcs_ptr->zf_current);
ZEND_MAP_PTR_NEW(ce->iterator_funcs_ptr); UNSERIALIZE_PTR(ce->iterator_funcs_ptr->zf_next);
} }
if (ce->ce_flags & ZEND_ACC_IMMUTABLE && ce->default_static_members_table) {
ZEND_MAP_PTR_NEW(ce->static_members_table);
} else { } else {
ZEND_MAP_PTR_INIT(ce->static_members_table, &ce->default_static_members_table); ZEND_MAP_PTR_INIT(ce->static_members_table, &ce->default_static_members_table);
UNSERIALIZE_PTR(ZEND_MAP_PTR(ce->iterator_funcs_ptr));
} }
} }

View file

@ -27,6 +27,7 @@
#include "zend_vm.h" #include "zend_vm.h"
#include "zend_constants.h" #include "zend_constants.h"
#include "zend_operators.h" #include "zend_operators.h"
#include "zend_interfaces.h"
#ifdef HAVE_OPCACHE_FILE_CACHE #ifdef HAVE_OPCACHE_FILE_CACHE
#define zend_set_str_gc_flags(str) do { \ #define zend_set_str_gc_flags(str) do { \
@ -905,14 +906,8 @@ static void zend_persist_class_entry(zval *zv)
} }
} }
if (ZEND_MAP_PTR(ce->iterator_funcs_ptr)) { if (ce->iterator_funcs_ptr) {
if (ce->ce_flags & ZEND_ACC_IMMUTABLE) { ce->iterator_funcs_ptr = zend_shared_memdup(ce->iterator_funcs_ptr, sizeof(zend_class_iterator_funcs));
ZEND_MAP_PTR_NEW(ce->iterator_funcs_ptr);
} else {
ZEND_MAP_PTR_INIT(ce->iterator_funcs_ptr, ZCG(arena_mem));
ZCG(arena_mem) = (void*)(((char*)ZCG(arena_mem)) + ZEND_ALIGNED_SIZE(sizeof(void*)));
ZEND_MAP_PTR_SET(ce->iterator_funcs_ptr, zend_shared_memdup_arena(ZEND_MAP_PTR_GET(ce->iterator_funcs_ptr), sizeof(zend_class_iterator_funcs)));
}
} }
} }
} }
@ -968,6 +963,20 @@ static int zend_update_parent_ce(zval *zv)
} }
} }
} }
if (ce->iterator_funcs_ptr) {
memset(ce->iterator_funcs_ptr, 0, sizeof(zend_class_iterator_funcs));
if (instanceof_function_ex(ce, zend_ce_aggregate, 1)) {
ce->iterator_funcs_ptr->zf_new_iterator = zend_hash_str_find_ptr(&ce->function_table, "getiterator", sizeof("getiterator") - 1);
}
if (instanceof_function_ex(ce, zend_ce_iterator, 1)) {
ce->iterator_funcs_ptr->zf_rewind = zend_hash_str_find_ptr(&ce->function_table, "rewind", sizeof("rewind") - 1);
ce->iterator_funcs_ptr->zf_valid = zend_hash_str_find_ptr(&ce->function_table, "valid", sizeof("valid") - 1);
ce->iterator_funcs_ptr->zf_key = zend_hash_str_find_ptr(&ce->function_table, "key", sizeof("key") - 1);
ce->iterator_funcs_ptr->zf_current = zend_hash_str_find_ptr(&ce->function_table, "current", sizeof("current") - 1);
ce->iterator_funcs_ptr->zf_next = zend_hash_str_find_ptr(&ce->function_table, "next", sizeof("next") - 1);
}
}
} }
/* update methods */ /* update methods */

View file

@ -431,11 +431,8 @@ static void zend_persist_class_entry_calc(zval *zv)
} }
} }
if (ZEND_MAP_PTR(ce->iterator_funcs_ptr)) { if (ce->iterator_funcs_ptr) {
if (!ZCG(is_immutable_class)) { ADD_SIZE(sizeof(zend_class_iterator_funcs));
ADD_ARENA_SIZE(sizeof(void*));
ADD_ARENA_SIZE(sizeof(zend_class_iterator_funcs));
}
} }
} }
} }

View file

@ -243,22 +243,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 iterator functions if ArrayIterator or derived. Check current's */
/* cache since only current is always required */ /* cache since only current is always required */
if (intern->std.handlers == &spl_handler_ArrayIterator) { if (intern->std.handlers == &spl_handler_ArrayIterator) {
zend_class_iterator_funcs *iterator_funcs_ptr = if (!class_type->iterator_funcs_ptr->zf_current) {
ZEND_MAP_PTR_GET(class_type->iterator_funcs_ptr); 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);
if (!iterator_funcs_ptr->zf_current) { class_type->iterator_funcs_ptr->zf_key = zend_hash_str_find_ptr(&class_type->function_table, "key", sizeof("key") - 1);
iterator_funcs_ptr->zf_rewind = zend_hash_str_find_ptr(&class_type->function_table, "rewind", sizeof("rewind") - 1); class_type->iterator_funcs_ptr->zf_current = zend_hash_str_find_ptr(&class_type->function_table, "current", sizeof("current") - 1);
iterator_funcs_ptr->zf_valid = zend_hash_str_find_ptr(&class_type->function_table, "valid", sizeof("valid") - 1); class_type->iterator_funcs_ptr->zf_next = zend_hash_str_find_ptr(&class_type->function_table, "next", sizeof("next") - 1);
iterator_funcs_ptr->zf_key = zend_hash_str_find_ptr(&class_type->function_table, "key", sizeof("key") - 1);
iterator_funcs_ptr->zf_current = zend_hash_str_find_ptr(&class_type->function_table, "current", sizeof("current") - 1);
iterator_funcs_ptr->zf_next = zend_hash_str_find_ptr(&class_type->function_table, "next", sizeof("next") - 1);
} }
if (inherited) { if (inherited) {
if (iterator_funcs_ptr->zf_rewind->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_REWIND; if (class_type->iterator_funcs_ptr->zf_rewind->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_REWIND;
if (iterator_funcs_ptr->zf_valid->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_VALID; if (class_type->iterator_funcs_ptr->zf_valid->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_VALID;
if (iterator_funcs_ptr->zf_key->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_KEY; if (class_type->iterator_funcs_ptr->zf_key->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_KEY;
if (iterator_funcs_ptr->zf_current->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_CURRENT; if (class_type->iterator_funcs_ptr->zf_current->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_CURRENT;
if (iterator_funcs_ptr->zf_next->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_NEXT; if (class_type->iterator_funcs_ptr->zf_next->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_NEXT;
} }
} }

View file

@ -207,7 +207,6 @@ static zend_object *spl_fixedarray_object_new_ex(zend_class_entry *class_type, z
spl_fixedarray_object *intern; spl_fixedarray_object *intern;
zend_class_entry *parent = class_type; zend_class_entry *parent = class_type;
int inherited = 0; int inherited = 0;
zend_class_iterator_funcs *iterator_funcs_ptr;
intern = zend_object_alloc(sizeof(spl_fixedarray_object), parent); intern = zend_object_alloc(sizeof(spl_fixedarray_object), parent);
@ -239,28 +238,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"); php_error_docref(NULL, E_COMPILE_ERROR, "Internal compiler error, Class is not child of SplFixedArray");
} }
iterator_funcs_ptr = ZEND_MAP_PTR_GET(class_type->iterator_funcs_ptr); if (!class_type->iterator_funcs_ptr->zf_current) {
if (!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);
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);
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);
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);
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);
iterator_funcs_ptr->zf_next = zend_hash_str_find_ptr(&class_type->function_table, "next", sizeof("next") - 1);
} }
if (inherited) { if (inherited) {
if (iterator_funcs_ptr->zf_rewind->common.scope != parent) { if (class_type->iterator_funcs_ptr->zf_rewind->common.scope != parent) {
intern->flags |= SPL_FIXEDARRAY_OVERLOADED_REWIND; intern->flags |= SPL_FIXEDARRAY_OVERLOADED_REWIND;
} }
if (iterator_funcs_ptr->zf_valid->common.scope != parent) { if (class_type->iterator_funcs_ptr->zf_valid->common.scope != parent) {
intern->flags |= SPL_FIXEDARRAY_OVERLOADED_VALID; intern->flags |= SPL_FIXEDARRAY_OVERLOADED_VALID;
} }
if (iterator_funcs_ptr->zf_key->common.scope != parent) { if (class_type->iterator_funcs_ptr->zf_key->common.scope != parent) {
intern->flags |= SPL_FIXEDARRAY_OVERLOADED_KEY; intern->flags |= SPL_FIXEDARRAY_OVERLOADED_KEY;
} }
if (iterator_funcs_ptr->zf_current->common.scope != parent) { if (class_type->iterator_funcs_ptr->zf_current->common.scope != parent) {
intern->flags |= SPL_FIXEDARRAY_OVERLOADED_CURRENT; intern->flags |= SPL_FIXEDARRAY_OVERLOADED_CURRENT;
} }
if (iterator_funcs_ptr->zf_next->common.scope != parent) { if (class_type->iterator_funcs_ptr->zf_next->common.scope != parent) {
intern->flags |= SPL_FIXEDARRAY_OVERLOADED_NEXT; intern->flags |= SPL_FIXEDARRAY_OVERLOADED_NEXT;
} }

View file

@ -494,8 +494,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 (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)) { if (instanceof_function(Z_OBJCE_P(iterator), zend_ce_aggregate)) {
zend_class_iterator_funcs *iterator_funcs_ptr = ZEND_MAP_PTR_GET(Z_OBJCE_P(iterator)->iterator_funcs_ptr); zend_call_method_with_0_params(iterator, Z_OBJCE_P(iterator), &Z_OBJCE_P(iterator)->iterator_funcs_ptr->zf_new_iterator, "getiterator", &aggregate_retval);
zend_call_method_with_0_params(iterator, Z_OBJCE_P(iterator), &iterator_funcs_ptr->zf_new_iterator, "getiterator", &aggregate_retval);
iterator = &aggregate_retval; iterator = &aggregate_retval;
} else { } else {
Z_ADDREF_P(iterator); Z_ADDREF_P(iterator);
@ -523,8 +522,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 (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)) { if (instanceof_function(Z_OBJCE_P(iterator), zend_ce_aggregate)) {
zend_class_iterator_funcs *iterator_funcs_ptr = ZEND_MAP_PTR_GET(Z_OBJCE_P(iterator)->iterator_funcs_ptr); zend_call_method_with_0_params(iterator, Z_OBJCE_P(iterator), &Z_OBJCE_P(iterator)->iterator_funcs_ptr->zf_new_iterator, "getiterator", &aggregate_retval);
zend_call_method_with_0_params(iterator, Z_OBJCE_P(iterator), &iterator_funcs_ptr->zf_new_iterator, "getiterator", &aggregate_retval);
iterator = &aggregate_retval; iterator = &aggregate_retval;
} else { } else {
Z_ADDREF_P(iterator); Z_ADDREF_P(iterator);
@ -1348,6 +1346,19 @@ static const zend_function_entry spl_funcs_RecursiveTreeIterator[] = {
PHP_FE_END PHP_FE_END
}; };
#if MBO_0
static int spl_dual_it_gets_implemented(zend_class_entry *interface, zend_class_entry *class_type)
{
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;
}
#endif
static zend_function *spl_dual_it_get_method(zend_object **object, zend_string *method, const zval *key) static zend_function *spl_dual_it_get_method(zend_object **object, zend_string *method, const zval *key)
{ {
zend_function *function_handler; zend_function *function_handler;
@ -1500,8 +1511,7 @@ static spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, z
ce = ce_cast; ce = ce_cast;
} }
if (instanceof_function(ce, zend_ce_aggregate)) { if (instanceof_function(ce, zend_ce_aggregate)) {
zend_class_iterator_funcs *iterator_funcs_ptr = ZEND_MAP_PTR_GET(ce->iterator_funcs_ptr); zend_call_method_with_0_params(zobject, ce, &ce->iterator_funcs_ptr->zf_new_iterator, "getiterator", &retval);
zend_call_method_with_0_params(zobject, ce, &iterator_funcs_ptr->zf_new_iterator, "getiterator", &retval);
if (EG(exception)) { if (EG(exception)) {
zval_ptr_dtor(&retval); zval_ptr_dtor(&retval);
return NULL; return NULL;

View file

@ -1028,11 +1028,8 @@ SPL_METHOD(MultipleIterator, rewind)
zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos); 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)) { while ((element = zend_hash_get_current_data_ptr_ex(&intern->storage, &intern->pos)) != NULL && !EG(exception)) {
zend_class_iterator_funcs *iterator_funcs_ptr;
it = &element->obj; it = &element->obj;
iterator_funcs_ptr = ZEND_MAP_PTR_GET(Z_OBJCE_P(it)->iterator_funcs_ptr); zend_call_method_with_0_params(it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs_ptr->zf_rewind, "rewind", NULL);
zend_call_method_with_0_params(it, Z_OBJCE_P(it), &iterator_funcs_ptr->zf_rewind, "rewind", NULL);
zend_hash_move_forward_ex(&intern->storage, &intern->pos); zend_hash_move_forward_ex(&intern->storage, &intern->pos);
} }
} }
@ -1054,11 +1051,8 @@ SPL_METHOD(MultipleIterator, next)
zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos); 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)) { while ((element = zend_hash_get_current_data_ptr_ex(&intern->storage, &intern->pos)) != NULL && !EG(exception)) {
zend_class_iterator_funcs *iterator_funcs_ptr;
it = &element->obj; it = &element->obj;
iterator_funcs_ptr = ZEND_MAP_PTR_GET(Z_OBJCE_P(it)->iterator_funcs_ptr); zend_call_method_with_0_params(it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs_ptr->zf_next, "next", NULL);
zend_call_method_with_0_params(it, Z_OBJCE_P(it), &iterator_funcs_ptr->zf_next, "next", NULL);
zend_hash_move_forward_ex(&intern->storage, &intern->pos); zend_hash_move_forward_ex(&intern->storage, &intern->pos);
} }
} }
@ -1087,11 +1081,8 @@ SPL_METHOD(MultipleIterator, valid)
zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos); 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)) { while ((element = zend_hash_get_current_data_ptr_ex(&intern->storage, &intern->pos)) != NULL && !EG(exception)) {
zend_class_iterator_funcs *iterator_funcs_ptr;
it = &element->obj; it = &element->obj;
iterator_funcs_ptr = ZEND_MAP_PTR_GET(Z_OBJCE_P(it)->iterator_funcs_ptr); zend_call_method_with_0_params(it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs_ptr->zf_valid, "valid", &retval);
zend_call_method_with_0_params(it, Z_OBJCE_P(it), &iterator_funcs_ptr->zf_valid, "valid", &retval);
if (!Z_ISUNDEF(retval)) { if (!Z_ISUNDEF(retval)) {
valid = (Z_TYPE(retval) == IS_TRUE); valid = (Z_TYPE(retval) == IS_TRUE);
@ -1126,11 +1117,8 @@ static void spl_multiple_iterator_get_all(spl_SplObjectStorage *intern, int get_
zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos); 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)) { while ((element = zend_hash_get_current_data_ptr_ex(&intern->storage, &intern->pos)) != NULL && !EG(exception)) {
zend_class_iterator_funcs *iterator_funcs_ptr;
it = &element->obj; it = &element->obj;
iterator_funcs_ptr = ZEND_MAP_PTR_GET(Z_OBJCE_P(it)->iterator_funcs_ptr); zend_call_method_with_0_params(it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs_ptr->zf_valid, "valid", &retval);
zend_call_method_with_0_params(it, Z_OBJCE_P(it), &iterator_funcs_ptr->zf_valid, "valid", &retval);
if (!Z_ISUNDEF(retval)) { if (!Z_ISUNDEF(retval)) {
valid = Z_TYPE(retval) == IS_TRUE; valid = Z_TYPE(retval) == IS_TRUE;
@ -1141,9 +1129,9 @@ static void spl_multiple_iterator_get_all(spl_SplObjectStorage *intern, int get_
if (valid) { if (valid) {
if (SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT == get_type) { if (SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT == get_type) {
zend_call_method_with_0_params(it, Z_OBJCE_P(it), &iterator_funcs_ptr->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 { } else {
zend_call_method_with_0_params(it, Z_OBJCE_P(it), &iterator_funcs_ptr->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)) { if (Z_ISUNDEF(retval)) {
zend_throw_exception(spl_ce_RuntimeException, "Failed to call sub iterator method", 0); zend_throw_exception(spl_ce_RuntimeException, "Failed to call sub iterator method", 0);