]> granicus.if.org Git - php/commitdiff
Introduced immutable arrays. They don't need to be copyed and may be used directly...
authorDmitry Stogov <dmitry@zend.com>
Thu, 29 May 2014 14:21:56 +0000 (18:21 +0400)
committerDmitry Stogov <dmitry@zend.com>
Thu, 29 May 2014 14:21:56 +0000 (18:21 +0400)
21 files changed:
Zend/zend.c
Zend/zend.h
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_constants.c
Zend/zend_execute.c
Zend/zend_hash.c
Zend/zend_hash.h
Zend/zend_types.h
Zend/zend_variables.h
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
ext/json/json.c
ext/opcache/Optimizer/zend_optimizer.c
ext/opcache/ZendAccelerator.c
ext/opcache/zend_accelerator_util_funcs.c
ext/opcache/zend_persist.c
ext/standard/array.c
ext/standard/http.c
ext/standard/var.c
ext/wddx/wddx.c

index 297fe2626749b65d89bfa6e7e5fd50f604b1d561..841fc38565cb46ecc1c31878093a652157df341e 100644 (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:
                        {
index 1968d76c226c53941febdbb3458594e6a7ed5f80..1a4d301f450370ab3215bf4d766d70225f900b1a 100644 (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)
 
index 23c38b889eff59fe2d64ba36172719a3be0308be..e1a4da0f736e243e491955dbbd00de68f1a8665d 100644 (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);
        }
index 1ff45ff6ce02ce713244e941f8bb512aa55f2e1f..5b5397844ffdc21e4d60dd8fe9acdf814f6f645e 100644 (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);
index 4f2cedb9af0d8aa9d5ac5bb756590ebe6f6aa2a6..4930d1fdd423516a014495efd79af8acca464e85 100644 (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);
        }
index ae66364aa991bebea87be67a968d21edddd9c4a6..37539d6ffecfca9c37b622c04218bedb574ecfd8 100644 (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:
index 5bf3e42b4ed9b7f27f091b2a7821d374a422f058..08b4cb5e4e436b3195a3d65a5b6484bb40ee2c8b 100644 (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) {
index c8f1e1c1764b76eedf62269f34f65fdcaefd1d5b..8660f8b6b70f0f596212e3ba5d9a948027d716d8 100644 (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 */
 
index 1503c5a41a27abf28aac0a41916a7784b746d49d..232fcbadc191bc21436744dc395f47f3f533146d 100644 (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))
 
index b85ef435cafe3231b83e9e99c8ca58ab1b71e816..282725a32520b89f2da0a7d73c1b269582cdd7d1 100644 (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);
index c27570c9dfd3d321d69cf30e27c4d48bfc05f6ea..0b5dde159922ae2bb5163ad2bec355f65587d621 100644 (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);
                        }
                }
index 4534be8639c6abd3bc12a6ccb13f55d01e9ea073..a5b678c9d247bcfe886a34922a4bd215b15bad8f 100644 (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);
                        }
                }
index 77607411251293cbe10f3ba7358e14a6ceafb454..e7e07ce2c1478c488e1e29664bef0311eabdab8e 100644 (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();
index 7244aafcc02a3f3faed6f44afca18aad62e025ac..0c68cc14d5494ae1b4e43bd3efb39fca2d18cb59 100644 (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);
index d89fa73d4cbe65718d9338aadb1134b7027f44db..70dbc2cb08f3115cc4070e76a763bffd6c9f2ed7 100644 (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;
        }
 }
index 1fe1d4c83fd5fa443fda98a4be29753c2e0db7bf..9def0183a4407545ab6bdb3c3eeddaa6b862da8c 100644 (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
index 1f5ee3af484a8a39175c52c5218af27c17a71ea5..ec1859b2d5c648c1ac2af1943f1b366d09d2a483 100644 (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
index 045b80c28be690629e6b51f88bc3a8882d844975..1398d45b7e65804ff0173a51a2250e8c9b187e6d 100644 (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) {
index 20e4023fc7937c6085a5c97de06e69e638f3a4b0..34b8e79389152aec37da72c03626b2585201de5e 100644 (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 */
index ba8a72973d38ff0239940429e3cb41037a914ebd..6abb70c0471eba4d4c7c9fedf6c08df7afda2dd8 100644 (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--;
                                                }
                                        }
index dc7ea834b620b4417ffda188d382faf86b8f68e8..a87f97fdcfda9371039016e9255847fa0a2344e7 100644 (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();
+               }
        }
 }
 /* }}} */