summaryrefslogtreecommitdiff
path: root/ext/spl/spl_array.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/spl/spl_array.c')
-rw-r--r--ext/spl/spl_array.c318
1 files changed, 177 insertions, 141 deletions
diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c
index 2835876e33..60cbac5726 100644
--- a/ext/spl/spl_array.c
+++ b/ext/spl/spl_array.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -82,21 +82,44 @@ static inline spl_array_object *spl_array_from_obj(zend_object *obj) /* {{{ */ {
#define Z_SPLARRAY_P(zv) spl_array_from_obj(Z_OBJ_P((zv)))
-static inline HashTable *spl_array_get_hash_table(spl_array_object* intern, int check_std_props) { /* {{{ */
- if (intern->ar_flags & SPL_ARRAY_IS_SELF
- || (check_std_props && (intern->ar_flags & SPL_ARRAY_STD_PROP_LIST))
- ) {
+static inline HashTable **spl_array_get_hash_table_ptr(spl_array_object* intern) { /* {{{ */
+ //??? TODO: Delay duplication for arrays; only duplicate for write operations
+ if (intern->ar_flags & SPL_ARRAY_IS_SELF) {
if (!intern->std.properties) {
rebuild_object_properties(&intern->std);
}
- return intern->std.properties;
+ return &intern->std.properties;
} else if (intern->ar_flags & SPL_ARRAY_USE_OTHER) {
spl_array_object *other = Z_SPLARRAY_P(&intern->array);
- return spl_array_get_hash_table(other, check_std_props);
+ return spl_array_get_hash_table_ptr(other);
+ } else if (Z_TYPE(intern->array) == IS_ARRAY) {
+ return &Z_ARRVAL(intern->array);
} else {
- return HASH_OF(&intern->array);
+ zend_object *obj = Z_OBJ(intern->array);
+ if (!obj->properties) {
+ rebuild_object_properties(obj);
+ } else if (GC_REFCOUNT(obj->properties) > 1) {
+ if (EXPECTED(!(GC_FLAGS(obj->properties) & IS_ARRAY_IMMUTABLE))) {
+ GC_REFCOUNT(obj->properties)--;
+ }
+ obj->properties = zend_array_dup(obj->properties);
+ }
+ return &obj->properties;
}
-} /* }}} */
+}
+/* }}} */
+
+static inline HashTable *spl_array_get_hash_table(spl_array_object* intern) { /* {{{ */
+ return *spl_array_get_hash_table_ptr(intern);
+}
+/* }}} */
+
+static inline void spl_array_replace_hash_table(spl_array_object* intern, HashTable *ht) { /* {{{ */
+ HashTable **ht_ptr = spl_array_get_hash_table_ptr(intern);
+ zend_array_destroy(*ht_ptr);
+ *ht_ptr = ht;
+}
+/* }}} */
static inline zend_bool spl_array_is_object(spl_array_object *intern) /* {{{ */
{
@@ -130,6 +153,10 @@ static zend_always_inline uint32_t *spl_array_get_pos_ptr(HashTable *ht, spl_arr
static void spl_array_object_free_storage(zend_object *object)
{
spl_array_object *intern = spl_array_from_obj(object);
+
+ if (intern->ht_iter != (uint32_t) -1) {
+ zend_hash_iterator_del(intern->ht_iter);
+ }
zend_object_std_dtor(&intern->std);
@@ -163,10 +190,12 @@ static zend_object *spl_array_object_new_ex(zend_class_entry *class_type, zval *
if (other->ar_flags & SPL_ARRAY_IS_SELF) {
ZVAL_UNDEF(&intern->array);
} else if (Z_OBJ_HT_P(orig) == &spl_handler_ArrayObject) {
- ZVAL_ARR(&intern->array, zend_array_dup(HASH_OF(&other->array)));
+ ZVAL_ARR(&intern->array,
+ zend_array_dup(spl_array_get_hash_table(other)));
} else {
ZEND_ASSERT(Z_OBJ_HT_P(orig) == &spl_handler_ArrayIterator);
- ZVAL_COPY(&intern->array, &other->array);
+ ZVAL_COPY(&intern->array, orig);
+ intern->ar_flags |= SPL_ARRAY_USE_OTHER;
}
} else {
ZVAL_COPY(&intern->array, orig);
@@ -259,23 +288,23 @@ static zend_object *spl_array_object_clone(zval *zobject)
}
/* }}} */
-static zval *spl_array_get_dimension_ptr(int check_inherited, zval *object, zval *offset, int type) /* {{{ */
+static zval *spl_array_get_dimension_ptr(int check_inherited, spl_array_object *intern, zval *offset, int type) /* {{{ */
{
zval *retval;
zend_long index;
zend_string *offset_key;
- spl_array_object *intern = Z_SPLARRAY_P(object);
- HashTable *ht = spl_array_get_hash_table(intern, 0);
+ HashTable *ht = spl_array_get_hash_table(intern);
if (!offset || Z_ISUNDEF_P(offset)) {
return &EG(uninitialized_zval);
}
- if ((type == BP_VAR_W || type == BP_VAR_RW) && (ht->u.v.nApplyCount > 0)) {
+ if ((type == BP_VAR_W || type == BP_VAR_RW) && intern->nApplyCount > 0) {
zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
- return &EG(error_zval);;
+ return &EG(error_zval);
}
+try_again:
switch (Z_TYPE_P(offset)) {
case IS_NULL:
offset_key = ZSTR_EMPTY_ALLOC();
@@ -355,6 +384,9 @@ num_index:
}
}
return retval;
+ case IS_REFERENCE:
+ ZVAL_DEREF(offset);
+ goto try_again;
default:
zend_error(E_WARNING, "Illegal offset type");
return (type == BP_VAR_W || type == BP_VAR_RW) ?
@@ -362,12 +394,21 @@ num_index:
}
} /* }}} */
+static int spl_array_has_dimension(zval *object, zval *offset, int check_empty);
+
static zval *spl_array_read_dimension_ex(int check_inherited, zval *object, zval *offset, int type, zval *rv) /* {{{ */
{
+ spl_array_object *intern = Z_SPLARRAY_P(object);
zval *ret;
- if (check_inherited) {
- spl_array_object *intern = Z_SPLARRAY_P(object);
+ if (check_inherited &&
+ (intern->fptr_offset_get || (type == BP_VAR_IS && intern->fptr_offset_has))) {
+ if (type == BP_VAR_IS) {
+ if (!spl_array_has_dimension(object, offset, 0)) {
+ return &EG(uninitialized_zval);
+ }
+ }
+
if (intern->fptr_offset_get) {
zval tmp;
if (!offset) {
@@ -385,13 +426,12 @@ static zval *spl_array_read_dimension_ex(int check_inherited, zval *object, zval
return &EG(uninitialized_zval);
}
}
- ret = spl_array_get_dimension_ptr(check_inherited, object, offset, type);
- //!!! FIXME?
- // ZVAL_COPY(result, ret);
+
+ ret = spl_array_get_dimension_ptr(check_inherited, intern, offset, type);
/* When in a write context,
* ZE has to be fooled into thinking this is in a reference set
- * by separating (if necessary) and returning as an is_ref=1 zval (even if refcount == 1)
+ * by separating (if necessary) and returning as IS_REFERENCE (with refcount == 1)
*/
if ((type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET) &&
@@ -428,29 +468,25 @@ static void spl_array_write_dimension_ex(int check_inherited, zval *object, zval
return;
}
- if (!offset) {
- ht = spl_array_get_hash_table(intern, 0);
- if (ht->u.v.nApplyCount > 0) {
- zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
- return;
- }
- if (Z_REFCOUNTED_P(value)) {
- Z_ADDREF_P(value);
- }
- zend_hash_next_index_insert(ht, value);
+ if (intern->nApplyCount > 0) {
+ zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
return;
}
if (Z_REFCOUNTED_P(value)) {
Z_ADDREF_P(value);
}
+
+ if (!offset) {
+ ht = spl_array_get_hash_table(intern);
+ zend_hash_next_index_insert(ht, value);
+ return;
+ }
+
+try_again:
switch (Z_TYPE_P(offset)) {
case IS_STRING:
- ht = spl_array_get_hash_table(intern, 0);
- if (ht->u.v.nApplyCount > 0) {
- zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
- return;
- }
+ ht = spl_array_get_hash_table(intern);
zend_symtable_update_ind(ht, Z_STR_P(offset), value);
return;
case IS_DOUBLE:
@@ -468,23 +504,19 @@ static void spl_array_write_dimension_ex(int check_inherited, zval *object, zval
case IS_LONG:
index = Z_LVAL_P(offset);
num_index:
- ht = spl_array_get_hash_table(intern, 0);
- if (ht->u.v.nApplyCount > 0) {
- zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
- return;
- }
+ ht = spl_array_get_hash_table(intern);
zend_hash_index_update(ht, index, value);
return;
case IS_NULL:
- ht = spl_array_get_hash_table(intern, 0);
- if (ht->u.v.nApplyCount > 0) {
- zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
- return;
- }
+ ht = spl_array_get_hash_table(intern);
zend_hash_next_index_insert(ht, value);
return;
+ case IS_REFERENCE:
+ ZVAL_DEREF(offset);
+ goto try_again;
default:
zend_error(E_WARNING, "Illegal offset type");
+ zval_ptr_dtor(value);
return;
}
} /* }}} */
@@ -507,13 +539,15 @@ static void spl_array_unset_dimension_ex(int check_inherited, zval *object, zval
return;
}
- switch(Z_TYPE_P(offset)) {
+ if (intern->nApplyCount > 0) {
+ zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
+ return;
+ }
+
+try_again:
+ switch (Z_TYPE_P(offset)) {
case IS_STRING:
- ht = spl_array_get_hash_table(intern, 0);
- if (ht->u.v.nApplyCount > 0) {
- zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
- return;
- }
+ ht = spl_array_get_hash_table(intern);
if (ht == &EG(symbol_table)) {
if (zend_delete_global_variable(Z_STR_P(offset))) {
zend_error(E_NOTICE,"Undefined index: %s", Z_STRVAL_P(offset));
@@ -529,6 +563,7 @@ static void spl_array_unset_dimension_ex(int check_inherited, zval *object, zval
} else {
zval_ptr_dtor(data);
ZVAL_UNDEF(data);
+ ht->u.v.flags |= HASH_FLAG_HAS_EMPTY_IND;
zend_hash_move_forward_ex(ht, spl_array_get_pos_ptr(ht, intern));
if (spl_array_is_object(intern)) {
spl_array_skip_protected(intern, ht);
@@ -557,15 +592,14 @@ static void spl_array_unset_dimension_ex(int check_inherited, zval *object, zval
case IS_LONG:
index = Z_LVAL_P(offset);
num_index:
- ht = spl_array_get_hash_table(intern, 0);
- if (ht->u.v.nApplyCount > 0) {
- zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
- return;
- }
+ ht = spl_array_get_hash_table(intern);
if (zend_hash_index_del(ht, index) == FAILURE) {
zend_error(E_NOTICE,"Undefined offset: %pd", index);
}
break;
+ case IS_REFERENCE:
+ ZVAL_DEREF(offset);
+ goto try_again;
default:
zend_error(E_WARNING, "Illegal offset type");
return;
@@ -584,11 +618,6 @@ static int spl_array_has_dimension_ex(int check_inherited, zval *object, zval *o
zval rv, *value = NULL, *tmp;
if (check_inherited && intern->fptr_offset_has) {
-//??? zval offset_tmp;
-//??? ZVAL_COPY_VALUE(&offset_tmp, offset);
-//??? SEPARATE_ARG_IF_REF(&offset_tmp);
-//??? zend_call_method_with_1_params(object, Z_OBJCE_P(object), &intern->fptr_offset_has, "offsetExists", &rv, &offset_tmp);
-//??? zval_ptr_dtor(&offset_tmp);
SEPARATE_ARG_IF_REF(offset);
zend_call_method_with_1_params(object, Z_OBJCE_P(object), &intern->fptr_offset_has, "offsetExists", &rv, offset);
zval_ptr_dtor(offset);
@@ -607,9 +636,10 @@ static int spl_array_has_dimension_ex(int check_inherited, zval *object, zval *o
}
if (!value) {
- HashTable *ht = spl_array_get_hash_table(intern, 0);
+ HashTable *ht = spl_array_get_hash_table(intern);
- switch(Z_TYPE_P(offset)) {
+try_again:
+ switch (Z_TYPE_P(offset)) {
case IS_STRING:
if ((tmp = zend_symtable_find(ht, Z_STR_P(offset))) != NULL) {
if (check_empty == 2) {
@@ -643,7 +673,9 @@ num_index:
return 0;
}
break;
-
+ case IS_REFERENCE:
+ ZVAL_DEREF(offset);
+ goto try_again;
default:
zend_error(E_WARNING, "Illegal offset type");
return 0;
@@ -730,7 +762,7 @@ SPL_METHOD(Array, offsetSet)
void spl_array_iterator_append(zval *object, zval *append_value) /* {{{ */
{
spl_array_object *intern = Z_SPLARRAY_P(object);
- HashTable *aht = spl_array_get_hash_table(intern, 0);
+ HashTable *aht = spl_array_get_hash_table(intern);
if (!aht) {
php_error_docref(NULL, E_NOTICE, "Array was modified outside object and is no longer an array");
@@ -778,22 +810,21 @@ SPL_METHOD(Array, getArrayCopy)
zval *object = getThis();
spl_array_object *intern = Z_SPLARRAY_P(object);
- RETURN_ARR(zend_array_dup(spl_array_get_hash_table(intern, 0)));
+ RETURN_ARR(zend_array_dup(spl_array_get_hash_table(intern)));
} /* }}} */
static HashTable *spl_array_get_properties(zval *object) /* {{{ */
{
spl_array_object *intern = Z_SPLARRAY_P(object);
- HashTable *result;
- if (intern->nApplyCount > 1) {
- php_error_docref(NULL, E_ERROR, "Nesting level too deep - recursive dependency?");
+ if (intern->ar_flags & SPL_ARRAY_STD_PROP_LIST) {
+ if (!intern->std.properties) {
+ rebuild_object_properties(&intern->std);
+ }
+ return intern->std.properties;
}
- intern->nApplyCount++;
- result = spl_array_get_hash_table(intern, 1);
- intern->nApplyCount--;
- return result;
+ return spl_array_get_hash_table(intern);
} /* }}} */
static HashTable* spl_array_get_debug_info(zval *obj, int *is_temp) /* {{{ */
@@ -870,11 +901,9 @@ static zval *spl_array_get_property_ptr_ptr(zval *object, zval *member, int type
if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
&& !std_object_handlers.has_property(object, member, 2, NULL)) {
- return spl_array_get_dimension_ptr(1, object, member, type);
+ return spl_array_get_dimension_ptr(1, intern, member, type);
}
- //!!! FIXME
- //return std_object_handlers.get_property_ptr_ptr(object, member, type, key);
- return NULL;
+ return std_object_handlers.get_property_ptr_ptr(object, member, type, cache_slot);
} /* }}} */
static int spl_array_has_property(zval *object, zval *member, int has_set_exists, void **cache_slot) /* {{{ */
@@ -910,8 +939,8 @@ static int spl_array_compare_objects(zval *o1, zval *o2) /* {{{ */
intern1 = Z_SPLARRAY_P(o1);
intern2 = Z_SPLARRAY_P(o2);
- ht1 = spl_array_get_hash_table(intern1, 0);
- ht2 = spl_array_get_hash_table(intern2, 0);
+ ht1 = spl_array_get_hash_table(intern1);
+ ht2 = spl_array_get_hash_table(intern2);
result = zend_compare_symbol_tables(ht1, ht2);
/* if we just compared std.properties, don't do it again */
@@ -966,7 +995,7 @@ static int spl_array_next_ex(spl_array_object *intern, HashTable *aht) /* {{{ */
static int spl_array_next(spl_array_object *intern) /* {{{ */
{
- HashTable *aht = spl_array_get_hash_table(intern, 0);
+ HashTable *aht = spl_array_get_hash_table(intern);
return spl_array_next_ex(intern, aht);
@@ -982,7 +1011,7 @@ static void spl_array_it_dtor(zend_object_iterator *iter) /* {{{ */
static int spl_array_it_valid(zend_object_iterator *iter) /* {{{ */
{
spl_array_object *object = Z_SPLARRAY_P(&iter->data);
- HashTable *aht = spl_array_get_hash_table(object, 0);
+ HashTable *aht = spl_array_get_hash_table(object);
if (object->ar_flags & SPL_ARRAY_OVERLOADED_VALID) {
return zend_user_it_valid(iter);
@@ -999,7 +1028,7 @@ static int spl_array_it_valid(zend_object_iterator *iter) /* {{{ */
static zval *spl_array_it_get_current_data(zend_object_iterator *iter) /* {{{ */
{
spl_array_object *object = Z_SPLARRAY_P(&iter->data);
- HashTable *aht = spl_array_get_hash_table(object, 0);
+ HashTable *aht = spl_array_get_hash_table(object);
if (object->ar_flags & SPL_ARRAY_OVERLOADED_CURRENT) {
return zend_user_it_get_current_data(iter);
@@ -1016,7 +1045,7 @@ static zval *spl_array_it_get_current_data(zend_object_iterator *iter) /* {{{ */
static void spl_array_it_get_current_key(zend_object_iterator *iter, zval *key) /* {{{ */
{
spl_array_object *object = Z_SPLARRAY_P(&iter->data);
- HashTable *aht = spl_array_get_hash_table(object, 0);
+ HashTable *aht = spl_array_get_hash_table(object);
if (object->ar_flags & SPL_ARRAY_OVERLOADED_KEY) {
zend_user_it_get_current_key(iter, key);
@@ -1033,7 +1062,7 @@ static void spl_array_it_get_current_key(zend_object_iterator *iter, zval *key)
static void spl_array_it_move_forward(zend_object_iterator *iter) /* {{{ */
{
spl_array_object *object = Z_SPLARRAY_P(&iter->data);
- HashTable *aht = spl_array_get_hash_table(object, 0);
+ HashTable *aht = spl_array_get_hash_table(object);
if (object->ar_flags & SPL_ARRAY_OVERLOADED_NEXT) {
zend_user_it_move_forward(iter);
@@ -1051,7 +1080,7 @@ static void spl_array_it_move_forward(zend_object_iterator *iter) /* {{{ */
static void spl_array_rewind(spl_array_object *intern) /* {{{ */
{
- HashTable *aht = spl_array_get_hash_table(intern, 0);
+ HashTable *aht = spl_array_get_hash_table(intern);
if (!aht) {
php_error_docref(NULL, E_NOTICE, "ArrayIterator::rewind(): Array was modified outside object and is no longer an array");
@@ -1087,13 +1116,13 @@ static void spl_array_set_array(zval *object, spl_array_object *intern, zval *ar
return;
}
- zval_ptr_dtor(&intern->array);
-
if (Z_TYPE_P(array) == IS_ARRAY) {
//??? TODO: try to avoid array duplication
+ zval_ptr_dtor(&intern->array);
ZVAL_DUP(&intern->array, array);
} else {
if (Z_OBJ_HT_P(array) == &spl_handler_ArrayObject || Z_OBJ_HT_P(array) == &spl_handler_ArrayIterator) {
+ zval_ptr_dtor(&intern->array);
if (just_array) {
spl_array_object *other = Z_SPLARRAY_P(array);
ar_flags = other->ar_flags & ~SPL_ARRAY_INT_MASK;
@@ -1107,11 +1136,14 @@ static void spl_array_set_array(zval *object, spl_array_object *intern, zval *ar
}
} else {
zend_object_get_properties_t handler = Z_OBJ_HANDLER_P(array, get_properties);
- ZVAL_COPY(&intern->array, array);
- if (handler != std_object_handlers.get_properties
- || !spl_array_get_hash_table(intern, 0)) {
- zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "Overloaded object of type %s is not compatible with %s", Z_OBJCE_P(array)->name, intern->std.ce->name);
+ if (handler != std_object_handlers.get_properties) {
+ zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0,
+ "Overloaded object of type %s is not compatible with %s",
+ ZSTR_VAL(Z_OBJCE_P(array)->name), ZSTR_VAL(intern->std.ce->name));
+ return;
}
+ zval_ptr_dtor(&intern->array);
+ ZVAL_COPY(&intern->array, array);
}
}
@@ -1153,8 +1185,8 @@ zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object,
}
/* }}} */
-/* {{{ proto void ArrayObject::__construct(array|object ar = array() [, int flags = 0 [, string iterator_class = "ArrayIterator"]])
- proto void ArrayIterator::__construct(array|object ar = array() [, int flags = 0])
+/* {{{ proto void ArrayObject::__construct([array|object ar = array() [, int flags = 0 [, string iterator_class = "ArrayIterator"]]])
+ proto void ArrayIterator::__construct([array|object ar = array() [, int flags = 0]])
Constructs a new array iterator from a path. */
SPL_METHOD(Array, __construct)
{
@@ -1264,7 +1296,12 @@ SPL_METHOD(Array, exchangeArray)
return;
}
- RETVAL_ARR(zend_array_dup(spl_array_get_hash_table(intern, 0)));
+ if (intern->nApplyCount > 0) {
+ zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
+ return;
+ }
+
+ RETVAL_ARR(zend_array_dup(spl_array_get_hash_table(intern)));
spl_array_set_array(object, intern, array, 0L, 1);
}
/* }}} */
@@ -1275,7 +1312,7 @@ SPL_METHOD(Array, getIterator)
{
zval *object = getThis();
spl_array_object *intern = Z_SPLARRAY_P(object);
- HashTable *aht = spl_array_get_hash_table(intern, 0);
+ HashTable *aht = spl_array_get_hash_table(intern);
if (zend_parse_parameters_none() == FAILURE) {
return;
@@ -1312,7 +1349,7 @@ SPL_METHOD(Array, seek)
zend_long opos, position;
zval *object = getThis();
spl_array_object *intern = Z_SPLARRAY_P(object);
- HashTable *aht = spl_array_get_hash_table(intern, 0);
+ HashTable *aht = spl_array_get_hash_table(intern);
int result;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &position) == FAILURE) {
@@ -1341,7 +1378,7 @@ SPL_METHOD(Array, seek)
int static spl_array_object_count_elements_helper(spl_array_object *intern, zend_long *count) /* {{{ */
{
- HashTable *aht = spl_array_get_hash_table(intern, 0);
+ HashTable *aht = spl_array_get_hash_table(intern);
HashPosition pos, *pos_ptr;
if (!aht) {
@@ -1406,23 +1443,19 @@ SPL_METHOD(Array, count)
static void spl_array_method(INTERNAL_FUNCTION_PARAMETERS, char *fname, int fname_len, int use_arg) /* {{{ */
{
spl_array_object *intern = Z_SPLARRAY_P(getThis());
- HashTable *aht = spl_array_get_hash_table(intern, 0);
+ HashTable *aht = spl_array_get_hash_table(intern);
zval function_name, params[2], *arg = NULL;
- uint32_t old_refcount;
ZVAL_STRINGL(&function_name, fname, fname_len);
- /* A tricky way to pass "aht" by reference, reset refcount */
- //??? It may be not safe, if user comparison handler accesses "aht"
- old_refcount = GC_REFCOUNT(aht);
- GC_REFCOUNT(aht) = 1;
ZVAL_NEW_EMPTY_REF(&params[0]);
ZVAL_ARR(Z_REFVAL(params[0]), aht);
+ GC_REFCOUNT(aht)++;
if (!use_arg) {
- aht->u.v.nApplyCount++;
+ intern->nApplyCount++;
call_user_function_ex(EG(function_table), NULL, &function_name, return_value, 1, params, 1, NULL);
- aht->u.v.nApplyCount--;
+ intern->nApplyCount--;
} else if (use_arg == SPL_ARRAY_METHOD_MAY_USER_ARG) {
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "|z", &arg) == FAILURE) {
zend_throw_exception(spl_ce_BadMethodCallException, "Function expects one argument at most", 0);
@@ -1431,25 +1464,31 @@ static void spl_array_method(INTERNAL_FUNCTION_PARAMETERS, char *fname, int fnam
if (arg) {
ZVAL_COPY_VALUE(&params[1], arg);
}
- aht->u.v.nApplyCount++;
+ intern->nApplyCount++;
call_user_function_ex(EG(function_table), NULL, &function_name, return_value, arg ? 2 : 1, params, 1, NULL);
- aht->u.v.nApplyCount--;
+ intern->nApplyCount--;
} else {
if (ZEND_NUM_ARGS() != 1 || zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "z", &arg) == FAILURE) {
zend_throw_exception(spl_ce_BadMethodCallException, "Function expects exactly one argument", 0);
goto exit;
}
ZVAL_COPY_VALUE(&params[1], arg);
- aht->u.v.nApplyCount++;
+ intern->nApplyCount++;
call_user_function_ex(EG(function_table), NULL, &function_name, return_value, 2, params, 1, NULL);
- aht->u.v.nApplyCount--;
+ intern->nApplyCount--;
}
exit:
- /* A tricky way to pass "aht" by reference, copy back and cleanup */
- GC_REFCOUNT(aht) = old_refcount;
- efree(Z_REF(params[0]));
- zend_string_free(Z_STR(function_name));
+ {
+ HashTable *new_ht = Z_ARRVAL_P(Z_REFVAL(params[0]));
+ if (aht != new_ht) {
+ spl_array_replace_hash_table(intern, new_ht);
+ } else {
+ GC_REFCOUNT(aht)--;
+ }
+ efree(Z_REF(params[0]));
+ zend_string_free(Z_STR(function_name));
+ }
} /* }}} */
#define SPL_ARRAY_METHOD(cname, fname, use_arg) \
@@ -1495,7 +1534,7 @@ SPL_METHOD(Array, current)
zval *object = getThis();
spl_array_object *intern = Z_SPLARRAY_P(object);
zval *entry;
- HashTable *aht = spl_array_get_hash_table(intern, 0);
+ HashTable *aht = spl_array_get_hash_table(intern);
if (zend_parse_parameters_none() == FAILURE) {
return;
@@ -1533,7 +1572,7 @@ SPL_METHOD(Array, key)
void spl_array_iterator_key(zval *object, zval *return_value) /* {{{ */
{
spl_array_object *intern = Z_SPLARRAY_P(object);
- HashTable *aht = spl_array_get_hash_table(intern, 0);
+ HashTable *aht = spl_array_get_hash_table(intern);
if (spl_array_object_verify_pos(intern, aht) == FAILURE) {
return;
@@ -1549,7 +1588,7 @@ SPL_METHOD(Array, next)
{
zval *object = getThis();
spl_array_object *intern = Z_SPLARRAY_P(object);
- HashTable *aht = spl_array_get_hash_table(intern, 0);
+ HashTable *aht = spl_array_get_hash_table(intern);
if (zend_parse_parameters_none() == FAILURE) {
return;
@@ -1569,7 +1608,7 @@ SPL_METHOD(Array, valid)
{
zval *object = getThis();
spl_array_object *intern = Z_SPLARRAY_P(object);
- HashTable *aht = spl_array_get_hash_table(intern, 0);
+ HashTable *aht = spl_array_get_hash_table(intern);
if (zend_parse_parameters_none() == FAILURE) {
return;
@@ -1589,7 +1628,7 @@ SPL_METHOD(Array, hasChildren)
{
zval *object = getThis(), *entry;
spl_array_object *intern = Z_SPLARRAY_P(object);
- HashTable *aht = spl_array_get_hash_table(intern, 0);
+ HashTable *aht = spl_array_get_hash_table(intern);
if (zend_parse_parameters_none() == FAILURE) {
return;
@@ -1613,7 +1652,7 @@ SPL_METHOD(Array, getChildren)
{
zval *object = getThis(), *entry, flags;
spl_array_object *intern = Z_SPLARRAY_P(object);
- HashTable *aht = spl_array_get_hash_table(intern, 0);
+ HashTable *aht = spl_array_get_hash_table(intern);
if (zend_parse_parameters_none() == FAILURE) {
return;
@@ -1649,7 +1688,7 @@ SPL_METHOD(Array, serialize)
{
zval *object = getThis();
spl_array_object *intern = Z_SPLARRAY_P(object);
- HashTable *aht = spl_array_get_hash_table(intern, 0);
+ HashTable *aht = spl_array_get_hash_table(intern);
zval members, flags;
php_serialize_data_t var_hash;
smart_str buf = {0};
@@ -1669,7 +1708,6 @@ SPL_METHOD(Array, serialize)
/* storage */
smart_str_appendl(&buf, "x:", 2);
- //!!! php_var_serialize need to be modified
php_var_serialize(&buf, &flags, &var_hash);
if (!(intern->ar_flags & SPL_ARRAY_IS_SELF)) {
@@ -1683,12 +1721,10 @@ SPL_METHOD(Array, serialize)
rebuild_object_properties(&intern->std);
}
- ZVAL_ARR(&members, zend_array_dup(intern->std.properties));
+ ZVAL_ARR(&members, intern->std.properties);
php_var_serialize(&buf, &members, &var_hash); /* finishes the string */
- zval_ptr_dtor(&members);
-
/* done */
PHP_VAR_SERIALIZE_DESTROY(var_hash);
@@ -1710,8 +1746,7 @@ SPL_METHOD(Array, unserialize)
size_t buf_len;
const unsigned char *p, *s;
php_unserialize_data_t var_hash;
- zval members, zflags;
- HashTable *aht;
+ zval *members, *zflags;
zend_long flags;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &buf, &buf_len) == FAILURE) {
@@ -1722,8 +1757,7 @@ SPL_METHOD(Array, unserialize)
return;
}
- aht = spl_array_get_hash_table(intern, 0);
- if (aht->u.v.nApplyCount > 0) {
+ if (intern->nApplyCount > 0) {
zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
return;
}
@@ -1737,14 +1771,15 @@ SPL_METHOD(Array, unserialize)
}
++p;
- if (!php_var_unserialize(&zflags, &p, s + buf_len, &var_hash) || Z_TYPE(zflags) != IS_LONG) {
+ zflags = var_tmp_var(&var_hash);
+ if (!php_var_unserialize(zflags, &p, s + buf_len, &var_hash) || Z_TYPE_P(zflags) != IS_LONG) {
goto outexcept;
}
--p; /* for ';' */
- flags = Z_LVAL(zflags);
+ flags = Z_LVAL_P(zflags);
/* flags needs to be verified and we also need to verify whether the next
- * thing we get is ';'. After that we require an 'm' or somethign else
+ * thing we get is ';'. After that we require an 'm' or something else
* where 'm' stands for members and anything else should be an array. If
* neither 'a' or 'm' follows we have an error. */
@@ -1760,9 +1795,11 @@ SPL_METHOD(Array, unserialize)
intern->ar_flags &= ~SPL_ARRAY_CLONE_MASK;
intern->ar_flags |= flags & SPL_ARRAY_CLONE_MASK;
zval_ptr_dtor(&intern->array);
+ ZVAL_UNDEF(&intern->array);
if (!php_var_unserialize(&intern->array, &p, s + buf_len, &var_hash)) {
goto outexcept;
}
+ var_push_dtor(&var_hash, &intern->array);
}
if (*p != ';') {
goto outexcept;
@@ -1775,18 +1812,15 @@ SPL_METHOD(Array, unserialize)
}
++p;
- ZVAL_UNDEF(&members);
- if (!php_var_unserialize(&members, &p, s + buf_len, &var_hash) || Z_TYPE(members) != IS_ARRAY) {
- zval_ptr_dtor(&members);
+ members = var_tmp_var(&var_hash);
+ if (!php_var_unserialize(members, &p, s + buf_len, &var_hash) || Z_TYPE_P(members) != IS_ARRAY) {
goto outexcept;
}
/* copy members */
- object_properties_load(&intern->std, Z_ARRVAL(members));
- zval_ptr_dtor(&members);
+ object_properties_load(&intern->std, Z_ARRVAL_P(members));
/* done reading $serialized */
-
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
return;
@@ -1797,9 +1831,11 @@ outexcept:
} /* }}} */
-/* {{{ arginfo and function tbale */
-ZEND_BEGIN_ARG_INFO(arginfo_array___construct, 0)
+/* {{{ arginfo and function table */
+ZEND_BEGIN_ARG_INFO_EX(arginfo_array___construct, 0, 0, 0)
ZEND_ARG_INFO(0, array)
+ ZEND_ARG_INFO(0, ar_flags)
+ ZEND_ARG_INFO(0, iterator_class)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_array_offsetGet, 0, 0, 1)