Introduced immutable arrays. They don't need to be copyed and may be used directly from SHM.

This commit is contained in:
Dmitry Stogov 2014-05-29 18:21:56 +04:00
parent bfff679d90
commit b3b616cf7e
21 changed files with 549 additions and 120 deletions

View File

@ -326,14 +326,17 @@ ZEND_API void zend_print_flat_zval_r(zval *expr TSRMLS_DC) /* {{{ */
switch (Z_TYPE_P(expr)) {
case IS_ARRAY:
ZEND_PUTS("Array (");
if (++Z_ARRVAL_P(expr)->u.v.nApplyCount>1) {
if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(expr)) &&
++Z_ARRVAL_P(expr)->u.v.nApplyCount>1) {
ZEND_PUTS(" *RECURSION*");
Z_ARRVAL_P(expr)->u.v.nApplyCount--;
return;
}
print_flat_hash(Z_ARRVAL_P(expr) TSRMLS_CC);
ZEND_PUTS(")");
Z_ARRVAL_P(expr)->u.v.nApplyCount--;
if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(expr))) {
Z_ARRVAL_P(expr)->u.v.nApplyCount--;
}
break;
case IS_OBJECT:
{
@ -385,13 +388,16 @@ ZEND_API void zend_print_zval_r_ex(zend_write_func_t write_func, zval *expr, int
switch (Z_TYPE_P(expr)) {
case IS_ARRAY:
ZEND_PUTS_EX("Array\n");
if (++Z_ARRVAL_P(expr)->u.v.nApplyCount>1) {
if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(expr)) &&
++Z_ARRVAL_P(expr)->u.v.nApplyCount>1) {
ZEND_PUTS_EX(" *RECURSION*");
Z_ARRVAL_P(expr)->u.v.nApplyCount--;
return;
}
print_hash(write_func, Z_ARRVAL_P(expr), indent, 0 TSRMLS_CC);
Z_ARRVAL_P(expr)->u.v.nApplyCount--;
if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(expr))) {
Z_ARRVAL_P(expr)->u.v.nApplyCount--;
}
break;
case IS_OBJECT:
{

View File

@ -737,17 +737,22 @@ END_EXTERN_C()
zval_copy_ctor_func(_zv); \
} \
} \
} else if (Z_IMMUTABLE_P(_zv)) { \
zval_copy_ctor_func(_zv); \
} \
} while (0)
#define SEPARATE_ZVAL_IF_NOT_REF(zv) do { \
zval *_zv = (zv); \
if (!Z_ISREF_P(_zv) && \
Z_COPYABLE_P(_zv) && \
Z_REFCOUNT_P(_zv) > 1) { \
Z_DELREF_P(_zv); \
zval_copy_ctor_func(_zv); \
} \
if (!Z_ISREF_P(_zv)) { \
if (Z_COPYABLE_P(_zv) && \
Z_REFCOUNT_P(_zv) > 1) { \
Z_DELREF_P(_zv); \
zval_copy_ctor_func(_zv); \
} else if (Z_IMMUTABLE_P(_zv)) { \
zval_copy_ctor_func(_zv); \
} \
} \
} while (0)
#define SEPARATE_ZVAL_IF_REF(zv) do { \
@ -765,14 +770,12 @@ END_EXTERN_C()
#define SEPARATE_ZVAL_TO_MAKE_IS_REF(zv) do { \
zval *__zv = (zv); \
if (!Z_ISREF_P(__zv)) { \
if (!Z_COPYABLE_P(__zv) || \
Z_REFCOUNT_P(__zv) == 1) { \
ZVAL_NEW_REF(__zv, __zv); \
} else { \
if (Z_COPYABLE_P(__zv) && \
Z_REFCOUNT_P(__zv) > 1) { \
Z_DELREF_P(__zv); \
ZVAL_NEW_REF(__zv, __zv); \
zval_copy_ctor_func(Z_REFVAL_P(__zv)); \
zval_copy_ctor_func(__zv); \
} \
ZVAL_NEW_REF(__zv, __zv); \
} \
} while (0)

View File

@ -5922,8 +5922,128 @@ void zend_do_add_array_element(znode *result, znode *expr, znode *offset, zend_b
void zend_do_end_array(znode *result, const znode *array_node TSRMLS_DC) /* {{{ */
{
int next_op_num = get_next_op_number(CG(active_op_array));
zend_op *init_opline = &CG(active_op_array)->opcodes[array_node->u.op.opline_num];
GET_NODE(result, init_opline->result);
zend_op *opline;
int i;
int constant_array = 0;
zval array;
zend_constant *c;
/* check if constructed array consists only from constants */
if ((init_opline->op1_type & (IS_UNUSED | IS_CONST)) &&
(init_opline->op2_type & (IS_UNUSED | IS_CONST))) {
if (next_op_num == array_node->u.op.opline_num + 1) {
constant_array = 1;
} else if ((init_opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT) == next_op_num - array_node->u.op.opline_num) {
opline = init_opline + 1;
i = next_op_num - array_node->u.op.opline_num - 1;
while (i > 0) {
if (opline->opcode != ZEND_ADD_ARRAY_ELEMENT ||
opline->op1_type != IS_CONST ||
!(opline->op2_type & (IS_UNUSED | IS_CONST))) {
break;
}
opline++;
i--;
}
if (i == 0) {
constant_array = 1;
}
}
}
if (constant_array) {
/* try to construct constant array */
zend_uint size;
long num;
zend_string *str;
if (init_opline->op1_type != IS_UNUSED) {
size = init_opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT;
} else {
size = 0;
}
ZVAL_NEW_ARR(&array);
zend_hash_init(Z_ARRVAL(array), size, NULL, ZVAL_PTR_DTOR, 0);
if (init_opline->op1_type != IS_UNUSED) {
/* Explicitly initialize array as not-packed if flag is set */
if (init_opline->extended_value & ZEND_ARRAY_NOT_PACKED) {
zend_hash_real_init(Z_ARRVAL(array), 0);
}
opline = init_opline;
i = next_op_num - array_node->u.op.opline_num;
while (i > 0 && constant_array) {
if (opline->op2_type == IS_CONST) {
switch (Z_TYPE(CONSTANT(opline->op2.constant))) {
case IS_LONG:
num = Z_LVAL(CONSTANT(opline->op2.constant));
num_index:
zend_hash_index_update(Z_ARRVAL(array), num, &CONSTANT(opline->op1.constant));
if (Z_REFCOUNTED(CONSTANT(opline->op1.constant))) Z_ADDREF(CONSTANT(opline->op1.constant));
break;
case IS_STRING:
str = Z_STR(CONSTANT(opline->op2.constant));
str_index:
zend_hash_update(Z_ARRVAL(array), str, &CONSTANT(opline->op1.constant));
if (Z_REFCOUNTED(CONSTANT(opline->op1.constant))) Z_ADDREF(CONSTANT(opline->op1.constant));
break;
case IS_DOUBLE:
num = zend_dval_to_lval(Z_DVAL(CONSTANT(opline->op2.constant)));
goto num_index;
case IS_FALSE:
num = 0;
goto num_index;
case IS_TRUE:
num = 1;
goto num_index;
case IS_NULL:
str = STR_EMPTY_ALLOC();
goto str_index;
default:
constant_array = 0;
break;
}
} else {
zend_hash_next_index_insert(Z_ARRVAL(array), &CONSTANT(opline->op1.constant));
if (Z_REFCOUNTED(CONSTANT(opline->op1.constant))) Z_ADDREF(CONSTANT(opline->op1.constant));
}
opline++;
i--;
}
if (!constant_array) {
zval_dtor(&array);
}
}
}
if (constant_array) {
/* remove run-time array construction and use constant array instead */
opline = &CG(active_op_array)->opcodes[next_op_num-1];
while (opline != init_opline) {
if (opline->op2_type == IS_CONST) {
zend_del_literal(CG(active_op_array), opline->op2.constant);
}
zend_del_literal(CG(active_op_array), opline->op1.constant);
opline--;
}
if (opline->op2_type == IS_CONST) {
zend_del_literal(CG(active_op_array), opline->op2.constant);
}
if (opline->op1_type == IS_CONST) {
zend_del_literal(CG(active_op_array), opline->op1.constant);
}
CG(active_op_array)->last = array_node->u.op.opline_num;
zend_make_immutable_array(&array TSRMLS_CC);
result->op_type = IS_CONST;
ZVAL_COPY_VALUE(&result->u.constant, &array);
} else {
GET_NODE(result, init_opline->result);
}
}
/* }}} */
@ -7368,6 +7488,43 @@ void zend_do_end_compilation(TSRMLS_D) /* {{{ */
}
/* }}} */
ZEND_API void zend_make_immutable_array(zval *zv TSRMLS_DC) /* {{{ */
{
zend_constant *c;
if (Z_IMMUTABLE_P(zv)) {
return;
}
Z_TYPE_FLAGS_P(zv) = IS_TYPE_IMMUTABLE;
Z_ARRVAL_P(zv)->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
/* store as an anounimus constant */
c = emalloc(sizeof(zend_constant));
ZVAL_COPY_VALUE(&c->value, zv);
c->flags = 0;
c->name = NULL;
c->module_number = PHP_USER_CONSTANT;
zend_hash_next_index_insert_ptr(EG(zend_constants), c);
}
/* }}} */
void zend_make_immutable_array_r(zval *zv TSRMLS_DC) /* {{{ */
{
zval *el;
if (Z_IMMUTABLE_P(zv)) {
return;
}
zend_make_immutable_array(zv TSRMLS_CC);
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zv), el) {
if (Z_TYPE_P(el) == IS_ARRAY) {
zend_make_immutable_array_r(el TSRMLS_CC);
}
} ZEND_HASH_FOREACH_END();
}
/* }}} */
void zend_do_constant_expression(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
{
if (ast->kind == ZEND_CONST) {
@ -7376,6 +7533,9 @@ void zend_do_constant_expression(znode *result, zend_ast *ast TSRMLS_DC) /* {{{
} else if (zend_ast_is_ct_constant(ast)) {
zend_ast_evaluate(&result->u.constant, ast, NULL TSRMLS_CC);
zend_ast_destroy(ast);
if (Z_TYPE(result->u.constant) == IS_ARRAY) {
zend_make_immutable_array_r(&result->u.constant TSRMLS_CC);
}
} else {
ZVAL_NEW_AST(&result->u.constant, ast);
}

View File

@ -471,6 +471,7 @@ typedef int (*unary_op_type)(zval *, zval * TSRMLS_DC);
typedef int (*binary_op_type)(zval *, zval *, zval * TSRMLS_DC);
ZEND_API unary_op_type get_unary_op(int opcode);
ZEND_API binary_op_type get_binary_op(int opcode);
ZEND_API void zend_make_immutable_array(zval *zv TSRMLS_DC);
void zend_do_while_cond(znode *expr, znode *close_bracket_token TSRMLS_DC);
void zend_do_while_end(const znode *while_token, const znode *close_bracket_token TSRMLS_DC);

View File

@ -32,7 +32,9 @@ void free_zend_constant(zval *zv)
zend_constant *c = Z_PTR_P(zv);
if (!(c->flags & CONST_PERSISTENT)) {
zval_dtor(&c->value);
if (Z_REFCOUNTED(c->value) || Z_IMMUTABLE(c->value)) {
_zval_dtor_func(Z_COUNTED(c->value) ZEND_FILE_LINE_CC);
}
} else {
zval_internal_dtor(&c->value);
}

View File

@ -1120,7 +1120,9 @@ static zend_always_inline void zend_fetch_dimension_address(zval *result, zval *
ZVAL_DEREF(container);
if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
if (container == container_ptr) {
if (Z_IMMUTABLE_P(container)) {
zval_copy_ctor(container);
} else if (container == container_ptr) {
SEPARATE_ZVAL(container);
}
fetch_from_array:

View File

@ -1174,7 +1174,7 @@ ZEND_API void zend_array_dup(HashTable *target, HashTable *source)
target->nTableSize = source->nTableSize;
target->pDestructor = source->pDestructor;
target->nInternalPointer = INVALID_IDX;
target->u.flags = (source->u.flags & ~HASH_FLAG_PERSISTENT);
target->u.flags = (source->u.flags & ~HASH_FLAG_PERSISTENT) | HASH_FLAG_APPLY_PROTECTION;
target_idx = 0;
if (target->nTableMask) {

View File

@ -669,10 +669,13 @@ static inline void *zend_hash_get_current_data_ptr_ex(HashTable *ht, HashPositio
_key = _p->key; \
_val = _z;
#define ZEND_HASH_APPLY_PROTECTION(ht) \
((ht)->u.flags & HASH_FLAG_APPLY_PROTECTION)
#define ZEND_HASH_APPLY_SHIFT 8
#define ZEND_HASH_GET_APPLY_COUNT(ht) (ht->u.flags >> ZEND_HASH_APPLY_SHIFT)
#define ZEND_HASH_INC_APPLY_COUNT(ht) (ht->u.flags += (1 << ZEND_HASH_APPLY_SHIFT))
#define ZEND_HASH_DEC_APPLY_COUNT(ht) (ht->u.flags -= (1 << ZEND_HASH_APPLY_SHIFT))
#define ZEND_HASH_GET_APPLY_COUNT(ht) ((ht)->u.flags >> ZEND_HASH_APPLY_SHIFT)
#define ZEND_HASH_INC_APPLY_COUNT(ht) ((ht)->u.flags += (1 << ZEND_HASH_APPLY_SHIFT))
#define ZEND_HASH_DEC_APPLY_COUNT(ht) ((ht)->u.flags -= (1 << ZEND_HASH_APPLY_SHIFT))
#endif /* ZEND_HASH_H */

View File

@ -282,6 +282,7 @@ static inline zend_uchar zval_get_type(const zval* pz) {
#define IS_TYPE_REFCOUNTED (1<<1)
#define IS_TYPE_COLLECTABLE (1<<2)
#define IS_TYPE_COPYABLE (1<<3)
#define IS_TYPE_IMMUTABLE (1<<4)
/* extended types */
#define IS_INTERNED_STRING_EX IS_STRING
@ -349,6 +350,9 @@ static inline zend_uchar zval_get_type(const zval* pz) {
#define Z_COPYABLE(zval) ((Z_TYPE_FLAGS(zval) & IS_TYPE_COPYABLE) != 0)
#define Z_COPYABLE_P(zval_p) Z_COPYABLE(*(zval_p))
#define Z_IMMUTABLE(zval) ((Z_TYPE_FLAGS(zval) & IS_TYPE_IMMUTABLE) != 0)
#define Z_IMMUTABLE_P(zval_p) Z_IMMUTABLE(*(zval_p))
/* the following Z_OPT_* macros make better code when Z_TYPE_INFO accessed before */
#define Z_OPT_TYPE(zval) (Z_TYPE_INFO(zval) & 0xff)
#define Z_OPT_TYPE_P(zval_p) Z_OPT_TYPE(*(zval_p))
@ -365,6 +369,9 @@ static inline zend_uchar zval_get_type(const zval* pz) {
#define Z_OPT_COPYABLE(zval) ((Z_TYPE_INFO(zval) & (IS_TYPE_COPYABLE << Z_TYPE_FLAGS_SHIFT)) != 0)
#define Z_OPT_COPYABLE_P(zval_p) Z_OPT_COPYABLE(*(zval_p))
#define Z_OPT_IMMUTABLE(zval) ((Z_TYPE_INFO(zval) & (IS_TYPE_IMMUTABLE << Z_TYPE_FLAGS_SHIFT)) != 0)
#define Z_OPT_IMMUTABLE_P(zval_p) Z_OPT_IMMUTABLE(*(zval_p))
#define Z_ISREF(zval) (Z_TYPE(zval) == IS_REFERENCE)
#define Z_ISREF_P(zval_p) Z_ISREF(*(zval_p))

View File

@ -42,8 +42,8 @@ ZEND_API void _zval_copy_ctor_func(zval *zvalue ZEND_FILE_LINE_DC);
static zend_always_inline void _zval_copy_ctor(zval *zvalue ZEND_FILE_LINE_DC)
{
if (Z_REFCOUNTED_P(zvalue)) {
if (Z_COPYABLE_P(zvalue)) {
if (Z_REFCOUNTED_P(zvalue) || Z_IMMUTABLE_P(zvalue)) {
if (Z_COPYABLE_P(zvalue) || Z_IMMUTABLE_P(zvalue)) {
_zval_copy_ctor_func(zvalue ZEND_FILE_LINE_RELAY_CC);
} else {
Z_ADDREF_P(zvalue);
@ -53,8 +53,8 @@ static zend_always_inline void _zval_copy_ctor(zval *zvalue ZEND_FILE_LINE_DC)
static zend_always_inline void _zval_opt_copy_ctor(zval *zvalue ZEND_FILE_LINE_DC)
{
if (Z_OPT_REFCOUNTED_P(zvalue)) {
if (Z_OPT_COPYABLE_P(zvalue)) {
if (Z_OPT_REFCOUNTED_P(zvalue) || Z_OPT_IMMUTABLE_P(zvalue)) {
if (Z_OPT_COPYABLE_P(zvalue) || Z_OPT_IMMUTABLE_P(zvalue)) {
_zval_copy_ctor_func(zvalue ZEND_FILE_LINE_RELAY_CC);
} else {
Z_ADDREF_P(zvalue);

View File

@ -3003,7 +3003,11 @@ ZEND_VM_HANDLER(65, ZEND_SEND_VAL, CONST|TMP, ANY)
top = zend_vm_stack_top_inc(TSRMLS_C);
ZVAL_COPY_VALUE(top, value);
if (OP1_TYPE == IS_CONST) {
zval_opt_copy_ctor(top);
/* Immutable arrays may be passed without copying ??? */
/* some internal functions may try to modify them !!! */
if (!Z_OPT_IMMUTABLE_P(top)) {
zval_opt_copy_ctor(top);
}
}
ZEND_VM_NEXT_OPCODE();
}
@ -3017,7 +3021,12 @@ ZEND_VM_HELPER(zend_send_by_var_helper, VAR|CV, ANY)
varptr = GET_OP1_ZVAL_PTR(BP_VAR_R);
top = zend_vm_stack_top_inc(TSRMLS_C);
if (Z_ISREF_P(varptr)) {
ZVAL_DUP(top, Z_REFVAL_P(varptr));
ZVAL_COPY_VALUE(top, Z_REFVAL_P(varptr));
/* Immutable arrays may be passed without copying ??? */
/* some internal functions may try to modify them !!! */
if (!Z_OPT_IMMUTABLE_P(top)) {
zval_opt_copy_ctor(top);
}
FREE_OP1();
} else {
ZVAL_COPY_VALUE(top, varptr);
@ -3056,6 +3065,10 @@ ZEND_VM_HANDLER(106, ZEND_SEND_VAR_NO_REF, VAR|CV, ANY)
if (!Z_ISREF_P(varptr)) {
ZVAL_NEW_REF(varptr, varptr);
}
// TODO: Try to avoid copying of immutable arrays ???
if (Z_OPT_IMMUTABLE_P(Z_REFVAL_P(varptr))) {
zval_opt_copy_ctor(Z_REFVAL_P(varptr));
}
if (OP1_TYPE == IS_CV) {
Z_ADDREF_P(varptr);
}
@ -3067,8 +3080,8 @@ ZEND_VM_HANDLER(106, ZEND_SEND_VAR_NO_REF, VAR|CV, ANY)
zend_error(E_STRICT, "Only variables should be passed by reference");
}
top = zend_vm_stack_top_inc(TSRMLS_C);
ZVAL_COPY_VALUE(top, varptr);
zval_opt_copy_ctor(top);
// TODO: Try to avoid copying of immutable arrays ???
ZVAL_DUP(top, varptr);
FREE_OP1_IF_VAR();
}
CHECK_EXCEPTION();
@ -3095,6 +3108,10 @@ ZEND_VM_HANDLER(67, ZEND_SEND_REF, VAR|CV, ANY)
}
if (Z_ISREF_P(varptr)) {
// TODO: Try to avoid copying of immutable arrays ???
if (Z_OPT_IMMUTABLE_P(Z_REFVAL_P(varptr))) {
zval_opt_copy_ctor(Z_REFVAL_P(varptr));
}
Z_ADDREF_P(varptr);
ZVAL_COPY_VALUE(top, varptr);
} else if (OP1_TYPE == IS_VAR &&
@ -3102,6 +3119,10 @@ ZEND_VM_HANDLER(67, ZEND_SEND_REF, VAR|CV, ANY)
ZVAL_COPY_VALUE(top, varptr);
SEPARATE_ZVAL_TO_MAKE_IS_REF(top);
} else {
// TODO: Try to avoid copying of immutable arrays ???
if (Z_OPT_IMMUTABLE_P(varptr)) {
zval_opt_copy_ctor(varptr);
}
SEPARATE_ZVAL_TO_MAKE_IS_REF(varptr);
Z_ADDREF_P(varptr);
ZVAL_COPY_VALUE(top, varptr);
@ -3126,7 +3147,12 @@ ZEND_VM_HANDLER(66, ZEND_SEND_VAR, VAR|CV, ANY)
varptr = GET_OP1_ZVAL_PTR(BP_VAR_R);
top = zend_vm_stack_top_inc(TSRMLS_C);
if (Z_ISREF_P(varptr)) {
ZVAL_DUP(top, Z_REFVAL_P(varptr));
ZVAL_COPY_VALUE(top, Z_REFVAL_P(varptr));
/* Immutable arrays may be passed without copying ??? */
/* some internal functions may try to modify them !!! */
if (!Z_OPT_IMMUTABLE_P(top)) {
zval_opt_copy_ctor(top);
}
FREE_OP1();
} else {
ZVAL_COPY_VALUE(top, varptr);
@ -3157,6 +3183,23 @@ ZEND_VM_C_LABEL(send_again):
ZEND_VM_STACK_GROW_IF_NEEDED(zend_hash_num_elements(ht));
if (OP1_TYPE != IS_CONST && OP1_TYPE != IS_TMP_VAR && Z_IMMUTABLE_P(args)) {
int i;
int separate = 0;
/* check if any of arguments are going to be passed by reference */
for (i = 0; i < zend_hash_num_elements(ht); i++) {
if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num + i)) {
separate = 1;
break;
}
}
if (separate) {
zval_copy_ctor(args);
ht = Z_ARRVAL_P(args);
}
}
ZEND_HASH_FOREACH_STR_KEY_VAL(ht, name, arg) {
if (name) {
zend_error(E_RECOVERABLE_ERROR, "Cannot unpack array with string keys");
@ -3167,9 +3210,13 @@ ZEND_VM_C_LABEL(send_again):
top = zend_vm_stack_top_inc(TSRMLS_C);
if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) {
SEPARATE_ZVAL_TO_MAKE_IS_REF(arg);
Z_ADDREF_P(arg);
ZVAL_COPY_VALUE(top, arg);
if (!Z_IMMUTABLE_P(args)) {
SEPARATE_ZVAL_TO_MAKE_IS_REF(arg);
Z_ADDREF_P(arg);
ZVAL_COPY_VALUE(top, arg);
} else {
ZVAL_DUP(top, arg);
}
} else if (Z_ISREF_P(arg)) {
ZVAL_DUP(top, Z_REFVAL_P(arg));
} else {
@ -4188,7 +4235,7 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET, CONST|TMP|VAR|CV, ANY)
{
USE_OPLINE
zend_free_op free_op1;
zval *array_ptr, *array_ref, iterator;
zval *array_ptr, *array_ref, iterator, tmp;
HashTable *fe_ht;
zend_object_iterator *iter = NULL;
zend_class_entry *ce = NULL;
@ -4209,6 +4256,8 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET, CONST|TMP|VAR|CV, ANY)
array_ref = array_ptr;
array_ptr = Z_REFVAL_P(array_ptr);
}
} else if (Z_IMMUTABLE_P(array_ptr)) {
zval_copy_ctor(array_ptr);
}
if (Z_REFCOUNTED_P(array_ref)) Z_ADDREF_P(array_ref);
} else if (Z_TYPE_P(array_ptr) == IS_OBJECT) {
@ -4232,8 +4281,6 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET, CONST|TMP|VAR|CV, ANY)
array_ptr = array_ref = GET_OP1_ZVAL_PTR(BP_VAR_R);
ZVAL_DEREF(array_ptr);
if (IS_OP1_TMP_FREE()) { /* IS_TMP_VAR */
zval tmp;
ZVAL_COPY_VALUE(&tmp, array_ptr);
array_ptr = &tmp;
if (Z_TYPE_P(array_ptr) == IS_OBJECT) {
@ -4249,6 +4296,14 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET, CONST|TMP|VAR|CV, ANY)
Z_ADDREF_P(array_ref);
}
}
} else if (Z_IMMUTABLE_P(array_ref)) {
if (OP1_TYPE == IS_CV) {
zval_copy_ctor(array_ref);
Z_ADDREF_P(array_ref);
} else {
ZVAL_DUP(&tmp, array_ref);
array_ptr = array_ref = &tmp;
}
} else if (Z_REFCOUNTED_P(array_ref)) {
if (OP1_TYPE == IS_CONST ||
(OP1_TYPE == IS_CV &&
@ -4257,8 +4312,6 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET, CONST|TMP|VAR|CV, ANY)
(OP1_TYPE == IS_VAR &&
!Z_ISREF_P(array_ref) &&
Z_REFCOUNT_P(array_ref) > 2)) {
zval tmp;
if (OP1_TYPE == IS_VAR) {
Z_DELREF_P(array_ref);
}
@ -4269,6 +4322,9 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET, CONST|TMP|VAR|CV, ANY)
ZVAL_UNREF(array_ref);
array_ptr = array_ref;
}
if (Z_IMMUTABLE_P(array_ptr)) {
zval_copy_ctor(array_ptr);
}
Z_ADDREF_P(array_ref);
}
}

View File

@ -754,6 +754,23 @@ send_again:
ZEND_VM_STACK_GROW_IF_NEEDED(zend_hash_num_elements(ht));
if (opline->op1_type != IS_CONST && opline->op1_type != IS_TMP_VAR && Z_IMMUTABLE_P(args)) {
int i;
int separate = 0;
/* check if any of arguments are going to be passed by reference */
for (i = 0; i < zend_hash_num_elements(ht); i++) {
if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num + i)) {
separate = 1;
break;
}
}
if (separate) {
zval_copy_ctor(args);
ht = Z_ARRVAL_P(args);
}
}
ZEND_HASH_FOREACH_STR_KEY_VAL(ht, name, arg) {
if (name) {
zend_error(E_RECOVERABLE_ERROR, "Cannot unpack array with string keys");
@ -764,9 +781,13 @@ send_again:
top = zend_vm_stack_top_inc(TSRMLS_C);
if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) {
SEPARATE_ZVAL_TO_MAKE_IS_REF(arg);
Z_ADDREF_P(arg);
ZVAL_COPY_VALUE(top, arg);
if (!Z_IMMUTABLE_P(args)) {
SEPARATE_ZVAL_TO_MAKE_IS_REF(arg);
Z_ADDREF_P(arg);
ZVAL_COPY_VALUE(top, arg);
} else {
ZVAL_DUP(top, arg);
}
} else if (Z_ISREF_P(arg)) {
ZVAL_DUP(top, Z_REFVAL_P(arg));
} else {
@ -2700,7 +2721,11 @@ static int ZEND_FASTCALL ZEND_SEND_VAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A
top = zend_vm_stack_top_inc(TSRMLS_C);
ZVAL_COPY_VALUE(top, value);
if (IS_CONST == IS_CONST) {
zval_opt_copy_ctor(top);
/* Immutable arrays may be passed without copying ??? */
/* some internal functions may try to modify them !!! */
if (!Z_OPT_IMMUTABLE_P(top)) {
zval_opt_copy_ctor(top);
}
}
ZEND_VM_NEXT_OPCODE();
}
@ -2981,7 +3006,7 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A
{
USE_OPLINE
zval *array_ptr, *array_ref, iterator;
zval *array_ptr, *array_ref, iterator, tmp;
HashTable *fe_ht;
zend_object_iterator *iter = NULL;
zend_class_entry *ce = NULL;
@ -3002,6 +3027,8 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A
array_ref = array_ptr;
array_ptr = Z_REFVAL_P(array_ptr);
}
} else if (Z_IMMUTABLE_P(array_ptr)) {
zval_copy_ctor(array_ptr);
}
if (Z_REFCOUNTED_P(array_ref)) Z_ADDREF_P(array_ref);
} else if (Z_TYPE_P(array_ptr) == IS_OBJECT) {
@ -3025,8 +3052,6 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A
array_ptr = array_ref = opline->op1.zv;
ZVAL_DEREF(array_ptr);
if (0) { /* IS_TMP_VAR */
zval tmp;
ZVAL_COPY_VALUE(&tmp, array_ptr);
array_ptr = &tmp;
if (Z_TYPE_P(array_ptr) == IS_OBJECT) {
@ -3042,6 +3067,14 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A
Z_ADDREF_P(array_ref);
}
}
} else if (Z_IMMUTABLE_P(array_ref)) {
if (IS_CONST == IS_CV) {
zval_copy_ctor(array_ref);
Z_ADDREF_P(array_ref);
} else {
ZVAL_DUP(&tmp, array_ref);
array_ptr = array_ref = &tmp;
}
} else if (Z_REFCOUNTED_P(array_ref)) {
if (IS_CONST == IS_CONST ||
(IS_CONST == IS_CV &&
@ -3050,8 +3083,6 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A
(IS_CONST == IS_VAR &&
!Z_ISREF_P(array_ref) &&
Z_REFCOUNT_P(array_ref) > 2)) {
zval tmp;
if (IS_CONST == IS_VAR) {
Z_DELREF_P(array_ref);
}
@ -3062,6 +3093,9 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A
ZVAL_UNREF(array_ref);
array_ptr = array_ref;
}
if (Z_IMMUTABLE_P(array_ptr)) {
zval_copy_ctor(array_ptr);
}
Z_ADDREF_P(array_ref);
}
}
@ -7807,7 +7841,11 @@ static int ZEND_FASTCALL ZEND_SEND_VAL_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG
top = zend_vm_stack_top_inc(TSRMLS_C);
ZVAL_COPY_VALUE(top, value);
if (IS_TMP_VAR == IS_CONST) {
zval_opt_copy_ctor(top);
/* Immutable arrays may be passed without copying ??? */
/* some internal functions may try to modify them !!! */
if (!Z_OPT_IMMUTABLE_P(top)) {
zval_opt_copy_ctor(top);
}
}
ZEND_VM_NEXT_OPCODE();
}
@ -8089,7 +8127,7 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG
{
USE_OPLINE
zend_free_op free_op1;
zval *array_ptr, *array_ref, iterator;
zval *array_ptr, *array_ref, iterator, tmp;
HashTable *fe_ht;
zend_object_iterator *iter = NULL;
zend_class_entry *ce = NULL;
@ -8110,6 +8148,8 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG
array_ref = array_ptr;
array_ptr = Z_REFVAL_P(array_ptr);
}
} else if (Z_IMMUTABLE_P(array_ptr)) {
zval_copy_ctor(array_ptr);
}
if (Z_REFCOUNTED_P(array_ref)) Z_ADDREF_P(array_ref);
} else if (Z_TYPE_P(array_ptr) == IS_OBJECT) {
@ -8133,8 +8173,6 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG
array_ptr = array_ref = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC);
ZVAL_DEREF(array_ptr);
if (1) { /* IS_TMP_VAR */
zval tmp;
ZVAL_COPY_VALUE(&tmp, array_ptr);
array_ptr = &tmp;
if (Z_TYPE_P(array_ptr) == IS_OBJECT) {
@ -8150,6 +8188,14 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG
Z_ADDREF_P(array_ref);
}
}
} else if (Z_IMMUTABLE_P(array_ref)) {
if (IS_TMP_VAR == IS_CV) {
zval_copy_ctor(array_ref);
Z_ADDREF_P(array_ref);
} else {
ZVAL_DUP(&tmp, array_ref);
array_ptr = array_ref = &tmp;
}
} else if (Z_REFCOUNTED_P(array_ref)) {
if (IS_TMP_VAR == IS_CONST ||
(IS_TMP_VAR == IS_CV &&
@ -8158,8 +8204,6 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG
(IS_TMP_VAR == IS_VAR &&
!Z_ISREF_P(array_ref) &&
Z_REFCOUNT_P(array_ref) > 2)) {
zval tmp;
if (IS_TMP_VAR == IS_VAR) {
Z_DELREF_P(array_ref);
}
@ -8170,6 +8214,9 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG
ZVAL_UNREF(array_ref);
array_ptr = array_ref;
}
if (Z_IMMUTABLE_P(array_ptr)) {
zval_copy_ctor(array_ptr);
}
Z_ADDREF_P(array_ref);
}
}
@ -12863,7 +12910,12 @@ static int ZEND_FASTCALL zend_send_by_var_helper_SPEC_VAR(ZEND_OPCODE_HANDLER_AR
varptr = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC);
top = zend_vm_stack_top_inc(TSRMLS_C);
if (Z_ISREF_P(varptr)) {
ZVAL_DUP(top, Z_REFVAL_P(varptr));
ZVAL_COPY_VALUE(top, Z_REFVAL_P(varptr));
/* Immutable arrays may be passed without copying ??? */
/* some internal functions may try to modify them !!! */
if (!Z_OPT_IMMUTABLE_P(top)) {
zval_opt_copy_ctor(top);
}
zval_ptr_dtor_nogc(free_op1.var);
} else {
ZVAL_COPY_VALUE(top, varptr);
@ -12902,6 +12954,10 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HAND
if (!Z_ISREF_P(varptr)) {
ZVAL_NEW_REF(varptr, varptr);
}
// TODO: Try to avoid copying of immutable arrays ???
if (Z_OPT_IMMUTABLE_P(Z_REFVAL_P(varptr))) {
zval_opt_copy_ctor(Z_REFVAL_P(varptr));
}
if (IS_VAR == IS_CV) {
Z_ADDREF_P(varptr);
}
@ -12913,8 +12969,8 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HAND
zend_error(E_STRICT, "Only variables should be passed by reference");
}
top = zend_vm_stack_top_inc(TSRMLS_C);
ZVAL_COPY_VALUE(top, varptr);
zval_opt_copy_ctor(top);
// TODO: Try to avoid copying of immutable arrays ???
ZVAL_DUP(top, varptr);
zval_ptr_dtor_nogc(free_op1.var);
}
CHECK_EXCEPTION();
@ -12941,6 +12997,10 @@ static int ZEND_FASTCALL ZEND_SEND_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
}
if (Z_ISREF_P(varptr)) {
// TODO: Try to avoid copying of immutable arrays ???
if (Z_OPT_IMMUTABLE_P(Z_REFVAL_P(varptr))) {
zval_opt_copy_ctor(Z_REFVAL_P(varptr));
}
Z_ADDREF_P(varptr);
ZVAL_COPY_VALUE(top, varptr);
} else if (IS_VAR == IS_VAR &&
@ -12948,6 +13008,10 @@ static int ZEND_FASTCALL ZEND_SEND_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
ZVAL_COPY_VALUE(top, varptr);
SEPARATE_ZVAL_TO_MAKE_IS_REF(top);
} else {
// TODO: Try to avoid copying of immutable arrays ???
if (Z_OPT_IMMUTABLE_P(varptr)) {
zval_opt_copy_ctor(varptr);
}
SEPARATE_ZVAL_TO_MAKE_IS_REF(varptr);
Z_ADDREF_P(varptr);
ZVAL_COPY_VALUE(top, varptr);
@ -12972,7 +13036,12 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
varptr = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC);
top = zend_vm_stack_top_inc(TSRMLS_C);
if (Z_ISREF_P(varptr)) {
ZVAL_DUP(top, Z_REFVAL_P(varptr));
ZVAL_COPY_VALUE(top, Z_REFVAL_P(varptr));
/* Immutable arrays may be passed without copying ??? */
/* some internal functions may try to modify them !!! */
if (!Z_OPT_IMMUTABLE_P(top)) {
zval_opt_copy_ctor(top);
}
zval_ptr_dtor_nogc(free_op1.var);
} else {
ZVAL_COPY_VALUE(top, varptr);
@ -13271,7 +13340,7 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
{
USE_OPLINE
zend_free_op free_op1;
zval *array_ptr, *array_ref, iterator;
zval *array_ptr, *array_ref, iterator, tmp;
HashTable *fe_ht;
zend_object_iterator *iter = NULL;
zend_class_entry *ce = NULL;
@ -13292,6 +13361,8 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
array_ref = array_ptr;
array_ptr = Z_REFVAL_P(array_ptr);
}
} else if (Z_IMMUTABLE_P(array_ptr)) {
zval_copy_ctor(array_ptr);
}
if (Z_REFCOUNTED_P(array_ref)) Z_ADDREF_P(array_ref);
} else if (Z_TYPE_P(array_ptr) == IS_OBJECT) {
@ -13315,8 +13386,6 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
array_ptr = array_ref = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC);
ZVAL_DEREF(array_ptr);
if (0) { /* IS_TMP_VAR */
zval tmp;
ZVAL_COPY_VALUE(&tmp, array_ptr);
array_ptr = &tmp;
if (Z_TYPE_P(array_ptr) == IS_OBJECT) {
@ -13332,6 +13401,14 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
Z_ADDREF_P(array_ref);
}
}
} else if (Z_IMMUTABLE_P(array_ref)) {
if (IS_VAR == IS_CV) {
zval_copy_ctor(array_ref);
Z_ADDREF_P(array_ref);
} else {
ZVAL_DUP(&tmp, array_ref);
array_ptr = array_ref = &tmp;
}
} else if (Z_REFCOUNTED_P(array_ref)) {
if (IS_VAR == IS_CONST ||
(IS_VAR == IS_CV &&
@ -13340,8 +13417,6 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
(IS_VAR == IS_VAR &&
!Z_ISREF_P(array_ref) &&
Z_REFCOUNT_P(array_ref) > 2)) {
zval tmp;
if (IS_VAR == IS_VAR) {
Z_DELREF_P(array_ref);
}
@ -13352,6 +13427,9 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
ZVAL_UNREF(array_ref);
array_ptr = array_ref;
}
if (Z_IMMUTABLE_P(array_ptr)) {
zval_copy_ctor(array_ptr);
}
Z_ADDREF_P(array_ref);
}
}
@ -29922,7 +30000,12 @@ static int ZEND_FASTCALL zend_send_by_var_helper_SPEC_CV(ZEND_OPCODE_HANDLER_ARG
varptr = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC);
top = zend_vm_stack_top_inc(TSRMLS_C);
if (Z_ISREF_P(varptr)) {
ZVAL_DUP(top, Z_REFVAL_P(varptr));
ZVAL_COPY_VALUE(top, Z_REFVAL_P(varptr));
/* Immutable arrays may be passed without copying ??? */
/* some internal functions may try to modify them !!! */
if (!Z_OPT_IMMUTABLE_P(top)) {
zval_opt_copy_ctor(top);
}
} else {
ZVAL_COPY_VALUE(top, varptr);
@ -29961,6 +30044,10 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDL
if (!Z_ISREF_P(varptr)) {
ZVAL_NEW_REF(varptr, varptr);
}
// TODO: Try to avoid copying of immutable arrays ???
if (Z_OPT_IMMUTABLE_P(Z_REFVAL_P(varptr))) {
zval_opt_copy_ctor(Z_REFVAL_P(varptr));
}
if (IS_CV == IS_CV) {
Z_ADDREF_P(varptr);
}
@ -29972,8 +30059,8 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDL
zend_error(E_STRICT, "Only variables should be passed by reference");
}
top = zend_vm_stack_top_inc(TSRMLS_C);
ZVAL_COPY_VALUE(top, varptr);
zval_opt_copy_ctor(top);
// TODO: Try to avoid copying of immutable arrays ???
ZVAL_DUP(top, varptr);
}
CHECK_EXCEPTION();
@ -30000,6 +30087,10 @@ static int ZEND_FASTCALL ZEND_SEND_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS
}
if (Z_ISREF_P(varptr)) {
// TODO: Try to avoid copying of immutable arrays ???
if (Z_OPT_IMMUTABLE_P(Z_REFVAL_P(varptr))) {
zval_opt_copy_ctor(Z_REFVAL_P(varptr));
}
Z_ADDREF_P(varptr);
ZVAL_COPY_VALUE(top, varptr);
} else if (IS_CV == IS_VAR &&
@ -30007,6 +30098,10 @@ static int ZEND_FASTCALL ZEND_SEND_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS
ZVAL_COPY_VALUE(top, varptr);
SEPARATE_ZVAL_TO_MAKE_IS_REF(top);
} else {
// TODO: Try to avoid copying of immutable arrays ???
if (Z_OPT_IMMUTABLE_P(varptr)) {
zval_opt_copy_ctor(varptr);
}
SEPARATE_ZVAL_TO_MAKE_IS_REF(varptr);
Z_ADDREF_P(varptr);
ZVAL_COPY_VALUE(top, varptr);
@ -30030,7 +30125,12 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS
varptr = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC);
top = zend_vm_stack_top_inc(TSRMLS_C);
if (Z_ISREF_P(varptr)) {
ZVAL_DUP(top, Z_REFVAL_P(varptr));
ZVAL_COPY_VALUE(top, Z_REFVAL_P(varptr));
/* Immutable arrays may be passed without copying ??? */
/* some internal functions may try to modify them !!! */
if (!Z_OPT_IMMUTABLE_P(top)) {
zval_opt_copy_ctor(top);
}
} else {
ZVAL_COPY_VALUE(top, varptr);
@ -30317,7 +30417,7 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS
{
USE_OPLINE
zval *array_ptr, *array_ref, iterator;
zval *array_ptr, *array_ref, iterator, tmp;
HashTable *fe_ht;
zend_object_iterator *iter = NULL;
zend_class_entry *ce = NULL;
@ -30338,6 +30438,8 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS
array_ref = array_ptr;
array_ptr = Z_REFVAL_P(array_ptr);
}
} else if (Z_IMMUTABLE_P(array_ptr)) {
zval_copy_ctor(array_ptr);
}
if (Z_REFCOUNTED_P(array_ref)) Z_ADDREF_P(array_ref);
} else if (Z_TYPE_P(array_ptr) == IS_OBJECT) {
@ -30361,8 +30463,6 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS
array_ptr = array_ref = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC);
ZVAL_DEREF(array_ptr);
if (0) { /* IS_TMP_VAR */
zval tmp;
ZVAL_COPY_VALUE(&tmp, array_ptr);
array_ptr = &tmp;
if (Z_TYPE_P(array_ptr) == IS_OBJECT) {
@ -30378,6 +30478,14 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS
Z_ADDREF_P(array_ref);
}
}
} else if (Z_IMMUTABLE_P(array_ref)) {
if (IS_CV == IS_CV) {
zval_copy_ctor(array_ref);
Z_ADDREF_P(array_ref);
} else {
ZVAL_DUP(&tmp, array_ref);
array_ptr = array_ref = &tmp;
}
} else if (Z_REFCOUNTED_P(array_ref)) {
if (IS_CV == IS_CONST ||
(IS_CV == IS_CV &&
@ -30386,8 +30494,6 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS
(IS_CV == IS_VAR &&
!Z_ISREF_P(array_ref) &&
Z_REFCOUNT_P(array_ref) > 2)) {
zval tmp;
if (IS_CV == IS_VAR) {
Z_DELREF_P(array_ref);
}
@ -30398,6 +30504,9 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS
ZVAL_UNREF(array_ref);
array_ptr = array_ref;
}
if (Z_IMMUTABLE_P(array_ptr)) {
zval_copy_ctor(array_ptr);
}
Z_ADDREF_P(array_ref);
}
}

View File

@ -258,7 +258,7 @@ static void json_encode_array(smart_str *buf, zval *val, int options TSRMLS_DC)
ZEND_HASH_FOREACH_KEY_VAL_IND(myht, index, key, data) {
ZVAL_DEREF(data);
tmp_ht = HASH_OF(data);
if (tmp_ht) {
if (tmp_ht && ZEND_HASH_APPLY_PROTECTION(tmp_ht)) {
ZEND_HASH_INC_APPLY_COUNT(tmp_ht);
}
@ -318,7 +318,7 @@ static void json_encode_array(smart_str *buf, zval *val, int options TSRMLS_DC)
}
}
if (tmp_ht) {
if (tmp_ht && ZEND_HASH_APPLY_PROTECTION(tmp_ht)) {
ZEND_HASH_DEC_APPLY_COUNT(tmp_ht);
}
} ZEND_HASH_FOREACH_END();

View File

@ -110,6 +110,9 @@ int zend_optimizer_add_literal(zend_op_array *op_array, zval *zv TSRMLS_DC)
int i = op_array->last_literal;
op_array->last_literal++;
op_array->literals = (zval*)erealloc(op_array->literals, op_array->last_literal * sizeof(zval));
if (Z_TYPE_P(zv) == IS_ARRAY) {
zend_make_immutable_array(zv TSRMLS_CC);
}
ZVAL_COPY_VALUE(&op_array->literals[i], zv);
Z_CACHE_SLOT(op_array->literals[i]) = -1;
//??? Z_SET_REFCOUNT(op_array->literals[i].constant, 2);

View File

@ -2333,7 +2333,6 @@ static int accel_clean_non_persistent_constant(zval *zv TSRMLS_DC)
if (c->flags & CONST_PERSISTENT) {
return ZEND_HASH_APPLY_STOP;
} else {
STR_RELEASE(c->name);
return ZEND_HASH_APPLY_REMOVE;
}
}

View File

@ -263,6 +263,10 @@ static inline void zend_clone_zval(zval *src, int bind TSRMLS_DC)
{
void *ptr;
if (Z_IMMUTABLE_P(src)) {
return;
}
#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
switch (Z_TYPE_P(src)) {
#else

View File

@ -101,6 +101,36 @@ static void zend_hash_persist(HashTable *ht, zend_persist_func_t pPersistElement
}
}
static void zend_hash_persist_immutable(HashTable *ht, zend_persist_func_t pPersistElement TSRMLS_DC)
{
uint idx;
Bucket *p;
if (!ht->nTableMask) {
ht->arHash = (zend_uint*)&uninitialized_bucket;
return;
}
if (ht->u.flags & HASH_FLAG_PACKED) {
ht->arData = zend_accel_memdup(ht->arData, sizeof(Bucket) * ht->nTableSize);
ht->arHash = (zend_uint*)&uninitialized_bucket;
} else {
ht->arData = zend_accel_memdup(ht->arData, (sizeof(Bucket) + sizeof(zend_uint)) * ht->nTableSize);
ht->arHash = (zend_uint*)(ht->arData + ht->nTableSize);
}
for (idx = 0; idx < ht->nNumUsed; idx++) {
p = ht->arData + idx;
if (Z_TYPE(p->val) == IS_UNDEF) continue;
/* persist bucket and key */
if (p->key) {
zend_accel_store_interned_string(p->key);
}
/* persist the data itself */
pPersistElement(&p->val TSRMLS_CC);
}
}
#if ZEND_EXTENSION_API_NO > PHP_5_5_X_API_NO
static zend_ast *zend_persist_ast(zend_ast *ast TSRMLS_DC)
{
@ -147,8 +177,13 @@ static void zend_persist_zval(zval *z TSRMLS_DC)
if (new_ptr) {
Z_ARR_P(z) = new_ptr;
} else {
zend_accel_store(Z_ARR_P(z), sizeof(zend_array));
zend_hash_persist(Z_ARRVAL_P(z), zend_persist_zval TSRMLS_CC);
if (Z_IMMUTABLE_P(z)) {
Z_ARR_P(z) = zend_accel_memdup(Z_ARR_P(z), sizeof(zend_array));
zend_hash_persist_immutable(Z_ARRVAL_P(z), zend_persist_zval TSRMLS_CC);
} else {
zend_accel_store(Z_ARR_P(z), sizeof(zend_array));
zend_hash_persist(Z_ARRVAL_P(z), zend_persist_zval TSRMLS_CC);
}
}
break;
#if ZEND_EXTENSION_API_NO > PHP_5_5_X_API_NO

View File

@ -266,10 +266,14 @@ PHPAPI int php_count_recursive(zval *array, long mode TSRMLS_DC) /* {{{ */
cnt = zend_hash_num_elements(Z_ARRVAL_P(array));
if (mode == COUNT_RECURSIVE) {
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(array), element) {
Z_ARRVAL_P(array)->u.v.nApplyCount++;
if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(array))) {
Z_ARRVAL_P(array)->u.v.nApplyCount++;
}
ZVAL_DEREF(element);
cnt += php_count_recursive(element, COUNT_RECURSIVE TSRMLS_CC);
Z_ARRVAL_P(array)->u.v.nApplyCount--;
if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(array))) {
Z_ARRVAL_P(array)->u.v.nApplyCount--;
}
} ZEND_HASH_FOREACH_END();
}
}
@ -1435,12 +1439,15 @@ static void php_compact_var(HashTable *eg_active_symbol_table, zval *return_valu
return;
}
Z_ARRVAL_P(entry)->u.v.nApplyCount++;
if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(entry))) {
Z_ARRVAL_P(entry)->u.v.nApplyCount++;
}
ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL_P(entry), value_ptr) {
php_compact_var(eg_active_symbol_table, return_value, value_ptr TSRMLS_CC);
} ZEND_HASH_FOREACH_END();
Z_ARRVAL_P(entry)->u.v.nApplyCount--;
if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(entry))) {
Z_ARRVAL_P(entry)->u.v.nApplyCount--;
}
}
}
/* }}} */
@ -2207,6 +2214,7 @@ PHPAPI int php_array_merge(HashTable *dest, HashTable *src, int recursive TSRMLS
zval *dest_zval = dest_entry;
HashTable *thash;
zval tmp;
int ret;
ZVAL_DEREF(src_zval);
ZVAL_DEREF(dest_zval);
@ -2241,18 +2249,16 @@ PHPAPI int php_array_merge(HashTable *dest, HashTable *src, int recursive TSRMLS
src_zval = &tmp;
}
if (Z_TYPE_P(src_zval) == IS_ARRAY) {
if (thash) {
if (thash && ZEND_HASH_APPLY_PROTECTION(thash)) {
thash->u.v.nApplyCount++;
}
if (!php_array_merge(Z_ARRVAL_P(dest_zval), Z_ARRVAL_P(src_zval), 1 TSRMLS_CC)) {
if (thash) {
thash->u.v.nApplyCount--;
}
return 0;
}
if (thash) {
ret = php_array_merge(Z_ARRVAL_P(dest_zval), Z_ARRVAL_P(src_zval), 1 TSRMLS_CC);
if (thash && ZEND_HASH_APPLY_PROTECTION(thash)) {
thash->u.v.nApplyCount--;
}
if (!ret) {
return 0;
}
} else {
if (Z_REFCOUNTED_P(src_entry)) {
Z_ADDREF_P(src_entry);
@ -2264,7 +2270,7 @@ PHPAPI int php_array_merge(HashTable *dest, HashTable *src, int recursive TSRMLS
if (Z_REFCOUNTED_P(src_entry)) {
Z_ADDREF_P(src_entry);
}
zend_hash_update(dest, string_key, src_entry);
zend_hash_add_new(dest, string_key, src_entry);
}
} else {
if (Z_REFCOUNTED_P(src_entry)) {
@ -2297,6 +2303,7 @@ PHPAPI int php_array_replace_recursive(HashTable *dest, HashTable *src TSRMLS_DC
zval *src_entry, *dest_entry, *src_zval, *dest_zval;
zend_string *string_key;
ulong num_key;
int ret;
ZEND_HASH_FOREACH_KEY_VAL(src, num_key, string_key, src_entry) {
src_zval = src_entry;
@ -2338,17 +2345,26 @@ PHPAPI int php_array_replace_recursive(HashTable *dest, HashTable *src TSRMLS_DC
return 0;
}
SEPARATE_ZVAL(dest_zval);
Z_ARRVAL_P(dest_zval)->u.v.nApplyCount++;
Z_ARRVAL_P(src_zval)->u.v.nApplyCount++;
if (!php_array_replace_recursive(Z_ARRVAL_P(dest_zval), Z_ARRVAL_P(src_zval) TSRMLS_CC)) {
if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(dest_zval))) {
Z_ARRVAL_P(dest_zval)->u.v.nApplyCount++;
}
if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(src_zval))) {
Z_ARRVAL_P(src_zval)->u.v.nApplyCount++;
}
ret = php_array_replace_recursive(Z_ARRVAL_P(dest_zval), Z_ARRVAL_P(src_zval) TSRMLS_CC);
if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(dest_zval))) {
Z_ARRVAL_P(dest_zval)->u.v.nApplyCount--;
}
if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(src_zval))) {
Z_ARRVAL_P(src_zval)->u.v.nApplyCount--;
}
if (!ret) {
return 0;
}
Z_ARRVAL_P(dest_zval)->u.v.nApplyCount--;
Z_ARRVAL_P(src_zval)->u.v.nApplyCount--;
} ZEND_HASH_FOREACH_END();
return 1;
@ -3850,6 +3866,9 @@ PHP_FUNCTION(array_multisort)
ZVAL_DEREF(arg);
if (Z_TYPE_P(arg) == IS_ARRAY) {
if (Z_IMMUTABLE_P(arg)) {
zval_copy_ctor(arg);
}
/* We see the next array, so we update the sort flags of
* the previous array and reset the sort flags. */
if (i > 0) {

View File

@ -135,9 +135,13 @@ PHPAPI int php_url_encode_hash_ex(HashTable *ht, smart_str *formstr,
*(p++) = 'B';
*p = '\0';
}
ht->u.v.nApplyCount++;
if (ZEND_HASH_APPLY_PROTECTION(ht)) {
ht->u.v.nApplyCount++;
}
php_url_encode_hash_ex(HASH_OF(zdata), formstr, NULL, 0, newprefix, newprefix_len, "%5D", 3, (Z_TYPE_P(zdata) == IS_OBJECT ? zdata : NULL), arg_sep, enc_type TSRMLS_CC);
ht->u.v.nApplyCount--;
if (ZEND_HASH_APPLY_PROTECTION(ht)) {
ht->u.v.nApplyCount--;
}
efree(newprefix);
} else if (Z_TYPE_P(zdata) == IS_NULL || Z_TYPE_P(zdata) == IS_RESOURCE) {
/* Skip these types */

View File

@ -132,7 +132,7 @@ again:
break;
case IS_ARRAY:
myht = Z_ARRVAL_P(struc);
if (++myht->u.v.nApplyCount > 1) {
if (ZEND_HASH_APPLY_PROTECTION(myht) && ++myht->u.v.nApplyCount > 1) {
PUTS("*RECURSION*\n");
--myht->u.v.nApplyCount;
return;
@ -143,7 +143,9 @@ again:
ZEND_HASH_FOREACH_KEY_VAL_IND(myht, num, key, val) {
php_array_element_dump(val, num, key, level TSRMLS_CC);
} ZEND_HASH_FOREACH_END();
--myht->u.v.nApplyCount;
if (ZEND_HASH_APPLY_PROTECTION(myht)) {
--myht->u.v.nApplyCount;
}
if (is_temp) {
zend_hash_destroy(myht);
efree(myht);
@ -301,7 +303,7 @@ again:
break;
case IS_ARRAY:
myht = Z_ARRVAL_P(struc);
if (myht->u.v.nApplyCount++ > 1) {
if (ZEND_HASH_APPLY_PROTECTION(myht) && myht->u.v.nApplyCount++ > 1) {
myht->u.v.nApplyCount--;
PUTS("*RECURSION*\n");
return;
@ -310,7 +312,9 @@ again:
ZEND_HASH_FOREACH_KEY_VAL_IND(myht, index, key, val) {
zval_array_element_dump(val, index, key, level TSRMLS_CC);
} ZEND_HASH_FOREACH_END();
myht->u.v.nApplyCount--;
if (ZEND_HASH_APPLY_PROTECTION(myht)) {
myht->u.v.nApplyCount--;
}
if (is_temp) {
zend_hash_destroy(myht);
efree(myht);
@ -491,7 +495,7 @@ again:
break;
case IS_ARRAY:
myht = Z_ARRVAL_P(struc);
if (myht->u.v.nApplyCount++ > 0) {
if (ZEND_HASH_APPLY_PROTECTION(myht) && myht->u.v.nApplyCount++ > 0) {
myht->u.v.nApplyCount--;
smart_str_appendl(buf, "NULL", 4);
zend_error(E_WARNING, "var_export does not handle circular references");
@ -505,7 +509,9 @@ again:
ZEND_HASH_FOREACH_KEY_VAL_IND(myht, index, key, val) {
php_array_element_export(val, index, key, level, buf TSRMLS_CC);
} ZEND_HASH_FOREACH_END();
myht->u.v.nApplyCount--;
if (ZEND_HASH_APPLY_PROTECTION(myht)) {
myht->u.v.nApplyCount--;
}
if (level > 1) {
buffer_append_spaces(buf, level - 1);
}
@ -943,11 +949,11 @@ again:
) {
smart_str_appendl(buf, "N;", 2);
} else {
if (Z_TYPE_P(data) == IS_ARRAY) {
if (Z_TYPE_P(data) == IS_ARRAY && ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(data))) {
Z_ARRVAL_P(data)->u.v.nApplyCount++;
}
php_var_serialize_intern(buf, data, var_hash TSRMLS_CC);
if (Z_TYPE_P(data) == IS_ARRAY) {
if (Z_TYPE_P(data) == IS_ARRAY && ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(data))) {
Z_ARRVAL_P(data)->u.v.nApplyCount--;
}
}

View File

@ -632,9 +632,13 @@ void php_wddx_serialize_var(wddx_packet *packet, zval *var, zend_string *name TS
php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "WDDX doesn't support circular references");
return;
}
ht->u.v.nApplyCount++;
if (ZEND_HASH_APPLY_PROTECTION(ht)) {
ht->u.v.nApplyCount++;
}
php_wddx_serialize_array(packet, var);
ht->u.v.nApplyCount--;
if (ZEND_HASH_APPLY_PROTECTION(ht)) {
ht->u.v.nApplyCount--;
}
break;
case IS_OBJECT:
@ -683,18 +687,24 @@ static void php_wddx_add_var(wddx_packet *packet, zval *name_var)
return;
}
ZEND_HASH_FOREACH_VAL(target_hash, val) {
if (is_array) {
target_hash->u.v.nApplyCount++;
}
if (Z_IMMUTABLE_P(name_var)) {
ZEND_HASH_FOREACH_VAL(target_hash, val) {
php_wddx_add_var(packet, val);
} ZEND_HASH_FOREACH_END();
} else {
ZEND_HASH_FOREACH_VAL(target_hash, val) {
if (is_array) {
target_hash->u.v.nApplyCount++;
}
ZVAL_DEREF(val);
php_wddx_add_var(packet, val);
ZVAL_DEREF(val);
php_wddx_add_var(packet, val);
if (is_array) {
target_hash->u.v.nApplyCount--;
}
} ZEND_HASH_FOREACH_END();
if (is_array) {
target_hash->u.v.nApplyCount--;
}
} ZEND_HASH_FOREACH_END();
}
}
}
/* }}} */