]> granicus.if.org Git - php/commitdiff
Reimplement iteration magic with HashTableIterators (see https://wiki.php.net/rfc...
authorDmitry Stogov <dmitry@zend.com>
Thu, 29 Jan 2015 18:05:02 +0000 (21:05 +0300)
committerDmitry Stogov <dmitry@zend.com>
Thu, 29 Jan 2015 18:05:02 +0000 (21:05 +0300)
19 files changed:
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_execute.c
Zend/zend_execute_API.c
Zend/zend_generators.c
Zend/zend_globals.h
Zend/zend_hash.c
Zend/zend_hash.h
Zend/zend_types.h
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
Zend/zend_vm_opcodes.c
Zend/zend_vm_opcodes.h
ext/opcache/Optimizer/block_pass.c
ext/opcache/Optimizer/optimize_temp_vars_5.c
ext/opcache/Optimizer/pass2.c
ext/standard/array.c
tests/lang/foreachLoop.013.phpt
tests/lang/foreachLoop.015.phpt

index e37fdd778cb10dafe9df7424558cb53edd5a0916..080b31562ac308006f53d95e0bc63f89b5bf6284 100644 (file)
@@ -829,7 +829,7 @@ static int generate_free_loop_var(znode *var) /* {{{ */
                {
                        zend_op *opline = get_next_op(CG(active_op_array));
 
-                       opline->opcode = ZEND_FREE;
+                       opline->opcode = var->flag ? ZEND_FE_FREE : ZEND_FREE;
                        SET_NODE(opline->op1, var);
                        SET_UNUSED(opline->op2);
                }
@@ -3398,6 +3398,7 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */
        opnum_reset = get_next_op_number(CG(active_op_array));
        opline = zend_emit_op(&reset_node, by_ref ? ZEND_FE_RESET_RW : ZEND_FE_RESET_R, &expr_node, NULL);
 
+       reset_node.flag = by_ref;
        zend_stack_push(&CG(loop_var_stack), &reset_node);
 
        opnum_fetch = get_next_op_number(CG(active_op_array));
@@ -3408,12 +3409,6 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */
 
        opline = zend_emit_op(NULL, ZEND_OP_DATA, NULL, NULL);
 
-       if (by_ref) {
-               /* Allocate temporary variable to keep HashTable value */
-               opline->op1_type = IS_TMP_VAR;
-               opline->op1.var = get_temporary_variable(CG(active_op_array));
-       }
-
        if (key_ast) {
                zend_make_tmp_result(&key_node, opline);
        }
@@ -3504,6 +3499,7 @@ void zend_compile_switch(zend_ast *ast) /* {{{ */
 
        zend_compile_expr(&expr_node, expr_ast);
 
+       expr_node.flag = 0;
        zend_stack_push(&CG(loop_var_stack), &expr_node);
 
        zend_begin_loop();
index 2d71ca25713b37087ff115252a5516f1732da30c..5239f565b3c0cf78b351ef6908e397d61b45ccc0 100644 (file)
@@ -95,7 +95,8 @@ typedef union _znode_op {
 } znode_op;
 
 typedef struct _znode { /* used only during compilation */
-       int op_type;
+       zend_uchar op_type;
+       zend_uchar flag;
        union {
                znode_op op;
                zval constant; /* replaced by literal/zv */
index 7a79defb059dc0f08a34daced02f5014e8e68b0f..d59aef1d1b16bc19e9100a0adb1b94e050bb5ab1 100644 (file)
@@ -1584,6 +1584,14 @@ static inline zend_brk_cont_element* zend_brk_cont(int nest_levels, int array_of
                                if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
                                        zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var));
                                }
+                       } else if (brk_opline->opcode == ZEND_FE_FREE) {
+                               if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
+                                       zval *var = EX_VAR(brk_opline->op1.var);
+                                       if (Z_FE_ITER_P(var) != (uint32_t)-1) {
+                                               zend_hash_iterator_del(Z_FE_ITER_P(var));
+                                       }
+                                       zval_ptr_dtor_nogc(var);
+                               }
                        }
                }
                array_offset = jmp_to->parent;
index c9da46d819382e0ab48bcdd20057ba5bebec0c50..c6a0d8f0c9abaa00450f26ebe5f801f195b3e66f 100644 (file)
@@ -183,6 +183,11 @@ void init_executor(void) /* {{{ */
 
        EG(scope) = NULL;
 
+       EG(ht_iterators_count) = sizeof(EG(ht_iterators_slots)) / sizeof(HashTableIterator);
+       EG(ht_iterators_used) = 0;
+       EG(ht_iterators) = EG(ht_iterators_slots);
+       memset(EG(ht_iterators), 0, sizeof(EG(ht_iterators_slots)));
+
        EG(active) = 1;
 }
 /* }}} */
@@ -373,6 +378,11 @@ void shutdown_executor(void) /* {{{ */
 
        zend_shutdown_fpu();
 
+       EG(ht_iterators_used) = 0;
+       if (EG(ht_iterators) != EG(ht_iterators_slots)) {
+               efree(EG(ht_iterators));
+       }
+
        EG(active) = 0;
 }
 /* }}} */
index f19bb850138b5e119097b9e507bf3b94a053cc61..1f25d07ea9dd06d4f0822423907cd88466b2f11c 100644 (file)
@@ -60,6 +60,12 @@ static void zend_generator_cleanup_unfinished_execution(zend_generator *generato
                                if (brk_opline->opcode == ZEND_FREE) {
                                        zval *var = EX_VAR(brk_opline->op1.var);
                                        zval_ptr_dtor_nogc(var);
+                               } else if (brk_opline->opcode == ZEND_FE_FREE) {
+                                       zval *var = EX_VAR(brk_opline->op1.var);
+                                       if (Z_FE_ITER_P(var) != (uint32_t)-1) {
+                                               zend_hash_iterator_del(Z_FE_ITER_P(var));
+                                       }
+                                       zval_ptr_dtor_nogc(var);
                                }
                        }
                }
index beca5ad631b332ea12089ad427056553a00a7d1c..abebb19ae39022ffec67c1b48b673f283909cbd0 100644 (file)
@@ -225,6 +225,11 @@ struct _zend_executor_globals {
        zend_bool active;
        zend_bool valid_symbol_table;
 
+       uint32_t           ht_iterators_count;     /* number of allocatd slots */
+       uint32_t           ht_iterators_used;      /* number of used slots */
+       HashTableIterator *ht_iterators;
+       HashTableIterator  ht_iterators_slots[16];
+
        void *saved_fpu_cw_ptr;
 #if XPFPA_HAVE_CW
        XPFPA_CW_DATATYPE saved_fpu_cw;
index 480ac64dd16d1d4f5c0fea298246a4fbccb0ef4e..dd175c7c00e24ff37e6c22ad0afb06e25445ffe8 100644 (file)
@@ -193,6 +193,144 @@ ZEND_API void zend_hash_set_apply_protection(HashTable *ht, zend_bool bApplyProt
        }
 }
 
+ZEND_API uint32_t zend_hash_iterator_add(HashTable *ht)
+{
+       HashTableIterator *iter = EG(ht_iterators);
+       HashTableIterator *end  = iter + EG(ht_iterators_count);
+       uint32_t idx;
+
+       if (EXPECTED(ht->u.v.nIteratorsCount != 255)) {
+               ht->u.v.nIteratorsCount++;
+       }
+       while (iter != end) {
+               if (iter->ht == NULL) {
+                       iter->ht = ht;
+                       iter->pos = ht->nInternalPointer;
+                       idx = iter - EG(ht_iterators);
+                       if (idx + 1 > EG(ht_iterators_used)) {
+                               EG(ht_iterators_used) = idx + 1;
+                       }
+                       return idx;
+               }
+               iter++;
+       }
+       if (EG(ht_iterators) == EG(ht_iterators_slots)) {
+               EG(ht_iterators) = emalloc(sizeof(HashTableIterator) * (EG(ht_iterators_count) + 8));
+               memcpy(EG(ht_iterators), EG(ht_iterators_slots), sizeof(HashTableIterator) * EG(ht_iterators_count));
+       } else {
+               EG(ht_iterators) = erealloc(EG(ht_iterators), sizeof(HashTableIterator) * (EG(ht_iterators_count) + 8));
+       }
+       iter = EG(ht_iterators) + EG(ht_iterators_count);
+       EG(ht_iterators_count) += 8;
+       iter->ht = ht;
+       iter->pos = ht->nInternalPointer;
+       memset(iter + 1, 0, sizeof(HashTableIterator) * 7);
+       idx = iter - EG(ht_iterators);
+       EG(ht_iterators_used) = idx + 1;
+       return idx;
+}
+
+ZEND_API HashPosition zend_hash_iterator_pos(uint32_t idx, HashTable *ht)
+{
+       HashTableIterator *iter = EG(ht_iterators) + idx;
+
+       ZEND_ASSERT(idx != (uint32_t)-1);
+       if (iter->pos == INVALID_IDX) {
+               return INVALID_IDX;
+       } else if (UNEXPECTED(iter->ht != ht)) {
+               if (EXPECTED(iter->ht) && EXPECTED(iter->ht->u.v.nIteratorsCount != 255)) {
+                       iter->ht->u.v.nIteratorsCount--;
+               }
+               if (EXPECTED(ht->u.v.nIteratorsCount != 255)) {
+                       ht->u.v.nIteratorsCount++;
+               }
+               iter->ht = ht;
+               iter->pos = ht->nInternalPointer;
+       }
+       return iter->pos;
+}
+
+ZEND_API void zend_hash_iterator_del(uint32_t idx)
+{
+       HashTableIterator *iter = EG(ht_iterators) + idx;
+
+       ZEND_ASSERT(idx != (uint32_t)-1);
+
+       if (EXPECTED(iter->ht) && EXPECTED(iter->ht->u.v.nIteratorsCount != 255)) {
+               iter->ht->u.v.nIteratorsCount--;
+       }
+       iter->ht = NULL;
+
+       if (idx == EG(ht_iterators_used) - 1) {
+               while (idx > 0 && EG(ht_iterators)[idx - 1].ht == NULL) {
+                       idx--;
+               }
+               EG(ht_iterators_used) = idx;
+       }
+}
+
+static zend_never_inline void _iterators_del(HashTable *ht)
+{
+       HashTableIterator *iter = EG(ht_iterators);
+       HashTableIterator *end  = iter + EG(ht_iterators_used);
+       uint32_t idx;
+
+       while (iter != end) {
+               if (iter->ht == ht) {
+                       iter->ht = NULL;
+               }
+               iter++;
+       }
+
+       idx = EG(ht_iterators_used);
+       while (idx > 0 && EG(ht_iterators)[idx - 1].ht == NULL) {
+               idx--;
+       }
+       EG(ht_iterators_used) = idx;
+}
+
+static zend_always_inline void iterators_del(HashTable *ht)
+{
+       if (UNEXPECTED(ht->u.v.nIteratorsCount)) {
+               _iterators_del(ht);
+       }
+}
+
+static zend_never_inline void _iterators_update(HashTable *ht, HashPosition pos)
+{
+       HashTableIterator *iter = EG(ht_iterators);
+       HashTableIterator *end  = iter + EG(ht_iterators_used);
+
+       while (iter != end) {
+               if (iter->ht == ht && iter->pos == ht->nInternalPointer) {
+                       iter->pos = pos;
+               }
+               iter++;
+       }
+}
+
+static zend_always_inline void iterators_update(HashTable *ht, HashPosition pos)
+{
+       if (UNEXPECTED(ht->u.v.nIteratorsCount)) {
+               _iterators_update(ht, pos);
+       }
+}
+
+ZEND_API void zend_hash_iterators_update(HashTable *ht, HashPosition pos)
+{
+       if (UNEXPECTED(ht->u.v.nIteratorsCount)) {
+               HashTableIterator *iter = EG(ht_iterators);
+               HashTableIterator *end  = iter + EG(ht_iterators_used);
+
+               while (iter != end) {
+                       if (iter->ht == ht && iter->pos == ht->nInternalPointer) {
+                               iter->pos = pos;
+                       }
+                       iter++;
+               }
+       }
+}
+
 static zend_always_inline Bucket *zend_hash_find_bucket(const HashTable *ht, zend_string *key)
 {
        zend_ulong h;
@@ -303,6 +441,7 @@ add_to_hash:
        idx = ht->nNumUsed++;
        ht->nNumOfElements++;
        if (ht->nInternalPointer == INVALID_IDX) {
+               iterators_update(ht, idx);
                ht->nInternalPointer = idx;
        }
        p = ht->arData + idx;
@@ -470,6 +609,7 @@ add_to_packed:
                }
                ht->nNumOfElements++;
                if (ht->nInternalPointer == INVALID_IDX) {
+                       iterators_update(ht, h);
                        ht->nInternalPointer = h;
                }
                if ((zend_long)h >= (zend_long)ht->nNextFreeElement) {
@@ -512,6 +652,7 @@ add_to_hash:
        idx = ht->nNumUsed++;
        ht->nNumOfElements++;
        if (ht->nInternalPointer == INVALID_IDX) {
+               iterators_update(ht, idx);
                ht->nInternalPointer = idx;
        }
        if ((zend_long)h >= (zend_long)ht->nNextFreeElement) {
@@ -600,6 +741,7 @@ ZEND_API int zend_hash_rehash(HashTable *ht)
                if (i != j) {
                        ht->arData[j] = ht->arData[i];
                        if (ht->nInternalPointer == i) {
+                               iterators_update(ht, j);
                                ht->nInternalPointer = j;
                        }
                }
@@ -632,9 +774,11 @@ static zend_always_inline void _zend_hash_del_el_ex(HashTable *ht, uint32_t idx,
                while (1) {
                        idx++;
                        if (idx >= ht->nNumUsed) {
+                               iterators_update(ht, INVALID_IDX);
                                ht->nInternalPointer = INVALID_IDX;
                                break;
                        } else if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
+                               iterators_update(ht, idx);
                                ht->nInternalPointer = idx;
                                break;
                        }
@@ -893,6 +1037,7 @@ ZEND_API void zend_hash_destroy(HashTable *ht)
                                } while (++p != end);
                        }
                }
+               iterators_del(ht);
        } else if (EXPECTED(!(ht->u.flags & HASH_FLAG_INITIALIZED))) {
                return;
        }
@@ -933,7 +1078,7 @@ ZEND_API void zend_array_destroy(HashTable *ht)
                                }
                        } while (++p != end);
                }
-
+               iterators_del(ht);
                SET_INCONSISTENT(HT_DESTROYED);
        } else if (EXPECTED(!(ht->u.flags & HASH_FLAG_INITIALIZED))) {
                return;
index 85f1890302a613697b3907f0d4cc4dc14236e71b..c8218f1112bc955e91a0d0dcd663a99f2d57967f 100644 (file)
@@ -50,8 +50,6 @@ typedef struct _zend_hash_key {
 
 typedef zend_bool (*merge_checker_func_t)(HashTable *target_ht, zval *source_data, zend_hash_key *hash_key, void *pParam);
 
-typedef uint32_t HashPosition;
-
 BEGIN_EXTERN_C()
 
 /* startup/shutdown */
@@ -227,6 +225,13 @@ void zend_hash_display(const HashTable *ht);
 
 ZEND_API int _zend_handle_numeric_str_ex(const char *key, size_t length, zend_ulong *idx);
 
+
+ZEND_API uint32_t     zend_hash_iterator_add(HashTable *ht);
+ZEND_API HashPosition zend_hash_iterator_pos(uint32_t idx, HashTable *ht);
+ZEND_API void         zend_hash_iterator_del(uint32_t idx);
+ZEND_API void         zend_hash_iterators_update(HashTable *ht, HashPosition pos);
+
+
 END_EXTERN_C()
 
 #define ZEND_INIT_SYMTABLE(ht)                                                         \
index aa5404139bd6bf087b4b23931688441a80588d75..dbe8c616df547ee3cfc6a5efe969d55a942657cb 100644 (file)
@@ -129,6 +129,7 @@ struct _zval_struct {
                uint32_t     lineno;               /* line number (for ast nodes) */
                uint32_t     num_args;             /* arguments number for EX(This) */
                uint32_t     fe_pos;               /* foreach position */
+               uint32_t     fe_iter_idx;          /* foreach iterator index */
        } u2;
 };
 
@@ -161,10 +162,11 @@ typedef struct _Bucket {
 typedef struct _HashTable {
        union {
                struct {
-                       ZEND_ENDIAN_LOHI_3(
+                       ZEND_ENDIAN_LOHI_4(
                                zend_uchar    flags,
                                zend_uchar    nApplyCount,
-                               uint16_t      reserve)
+                               zend_uchar    nIteratorsCount,
+                               zend_uchar    reserve)
                } v;
                uint32_t flags;
        } u;
@@ -179,6 +181,13 @@ typedef struct _HashTable {
        dtor_func_t       pDestructor;
 } HashTable;
 
+typedef uint32_t HashPosition;
+
+typedef struct _HashTableIterator {
+       HashTable    *ht;
+       HashPosition  pos;
+} HashTableIterator;
+
 struct _zend_array {
        zend_refcounted   gc;
        HashTable         ht;
@@ -265,6 +274,9 @@ static zend_always_inline zend_uchar zval_get_type(const zval* pz) {
 #define Z_FE_POS(zval)                         (zval).u2.fe_pos
 #define Z_FE_POS_P(zval_p)                     Z_FE_POS(*(zval_p))
 
+#define Z_FE_ITER(zval)                                (zval).u2.fe_iter_idx
+#define Z_FE_ITER_P(zval_p)                    Z_FE_ITER(*(zval_p))
+
 #define Z_COUNTED(zval)                                (zval).value.counted
 #define Z_COUNTED_P(zval_p)                    Z_COUNTED(*(zval_p))
 
index 5ddc903888b6fcdf96ab0d73adc1f9d90e2cee2b..245bc0b68a1a47bbed5f23320f4b0658e3ed566e 100644 (file)
@@ -2138,6 +2138,21 @@ ZEND_VM_HANDLER(70, ZEND_FREE, TMPVAR, ANY)
        ZEND_VM_NEXT_OPCODE();
 }
 
+ZEND_VM_HANDLER(127, ZEND_FE_FREE, TMPVAR, ANY)
+{
+       zval *var;
+       USE_OPLINE
+
+       SAVE_OPLINE();
+       var = EX_VAR(opline->op1.var);
+       if (Z_FE_ITER_P(var) != (uint32_t)-1) {
+               zend_hash_iterator_del(Z_FE_ITER_P(var));
+       }
+       zval_ptr_dtor_nogc(var);
+       CHECK_EXCEPTION();
+       ZEND_VM_NEXT_OPCODE();
+}
+
 ZEND_VM_HANDLER(54, ZEND_ADD_CHAR, TMP|UNUSED, CONST)
 {
        USE_OPLINE
@@ -3821,6 +3836,14 @@ ZEND_VM_HANDLER(100, ZEND_GOTO, ANY, CONST)
                if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
                        zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var));
                }
+       } else if (brk_opline->opcode == ZEND_FE_FREE) {
+               if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
+                       zval *var = EX_VAR(brk_opline->op1.var);
+                       if (Z_FE_ITER_P(var) != (uint32_t)-1) {
+                               zend_hash_iterator_del(Z_FE_ITER_P(var));
+                       }
+                       zval_ptr_dtor_nogc(var);
+               }
        }
        ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op1));
 }
@@ -4758,8 +4781,7 @@ ZEND_VM_HANDLER(125, ZEND_FE_RESET_RW, CONST|TMP|VAR|CV, ANY)
                iter->index = -1; /* will be set to 0 before using next handler */
 
                ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
-               Z_FE_POS_P(EX_VAR(opline->result.var)) = INVALID_IDX;
-               ZVAL_PTR(EX_VAR((opline+2)->op1.var), NULL);
+               Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
 
                if (OP1_TYPE == IS_VAR) {
                        FREE_OP1_VAR_PTR();
@@ -4798,6 +4820,7 @@ ZEND_VM_HANDLER(125, ZEND_FE_RESET_RW, CONST|TMP|VAR|CV, ANY)
                while (1) {
                        if (pos >= fe_ht->nNumUsed) {
                                FREE_OP1_VAR_PTR();
+                               Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
                                ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
                        }
                        p = fe_ht->arData + pos;
@@ -4811,8 +4834,8 @@ ZEND_VM_HANDLER(125, ZEND_FE_RESET_RW, CONST|TMP|VAR|CV, ANY)
                        }
                        pos++;
                }
-               Z_FE_POS_P(EX_VAR(opline->result.var)) = fe_ht->nInternalPointer = pos;
-               ZVAL_PTR(EX_VAR((opline+2)->op1.var), fe_ht);
+               fe_ht->nInternalPointer = pos;
+               Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht);
 
                FREE_OP1_VAR_PTR();
                CHECK_EXCEPTION();
@@ -4820,6 +4843,7 @@ ZEND_VM_HANDLER(125, ZEND_FE_RESET_RW, CONST|TMP|VAR|CV, ANY)
        } else {
                zend_error(E_WARNING, "Invalid argument supplied for foreach()");
                ZVAL_UNDEF(EX_VAR(opline->result.var));
+               Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
                if (OP1_TYPE == IS_VAR) {
                        FREE_OP1_VAR_PTR();
                } else {
@@ -4990,21 +5014,7 @@ ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY)
        ZVAL_DEREF(array);
        if (EXPECTED(Z_TYPE_P(array) == IS_ARRAY)) {
                fe_ht = Z_ARRVAL_P(array);
-               pos = Z_FE_POS_P(EX_VAR(opline->op1.var));
-               if (UNEXPECTED(pos == INVALID_IDX)) {
-                       /* reached end of iteration */
-                       ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
-               } else {
-                       if (Z_PTR_P(EX_VAR((opline+1)->op1.var)) != fe_ht) {
-                               pos = fe_ht->nInternalPointer;
-                       }
-                       SEPARATE_ARRAY(array);
-                       fe_ht = Z_ARRVAL_P(array);
-                       Z_PTR_P(EX_VAR((opline+1)->op1.var)) = fe_ht;
-               }
-//???          if (pos != fe_ht->nInternalPointer) {
-//???                  //...
-//???          }
+               pos = zend_hash_iterator_pos(Z_FE_ITER_P(EX_VAR(opline->op1.var)), fe_ht);
                while (1) {
                        if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
                                /* reached end of iteration */
@@ -5048,7 +5058,8 @@ ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY)
                                break;
                        }
                }
-               Z_FE_POS_P(EX_VAR(opline->op1.var)) = fe_ht->nInternalPointer = pos;
+               EG(ht_iterators)[Z_FE_ITER_P(EX_VAR(opline->op1.var))].pos =
+                       fe_ht->nInternalPointer = pos;
                ZEND_VM_INC_OPCODE();
                ZEND_VM_NEXT_OPCODE();
        } else if (EXPECTED(Z_TYPE_P(array) == IS_OBJECT)) {
@@ -5059,19 +5070,7 @@ ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY)
                        zend_object *zobj = Z_OBJ_P(array);
 
                        fe_ht = Z_OBJPROP_P(array);
-                       pos = Z_FE_POS_P(EX_VAR(opline->op1.var));
-                       if (UNEXPECTED(pos == INVALID_IDX)) {
-                               /* reached end of iteration */
-                               ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
-                       } else {
-                               if (Z_PTR_P(EX_VAR((opline+1)->op1.var)) != fe_ht) {
-                                       pos = fe_ht->nInternalPointer;
-                               }
-                               Z_PTR_P(EX_VAR((opline+1)->op1.var)) = fe_ht;
-                       }
-//???                  if (pos != fe_ht->nInternalPointer) {
-//???
-//???                  }
+                       pos = zend_hash_iterator_pos(Z_FE_ITER_P(EX_VAR(opline->op1.var)), fe_ht);
                        while (1) {
                                if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
                                        /* reached end of iteration */
@@ -5129,7 +5128,8 @@ ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY)
                                        break;
                                }
                        }
-                       Z_FE_POS_P(EX_VAR(opline->op1.var)) = fe_ht->nInternalPointer = pos;
+                       EG(ht_iterators)[Z_FE_ITER_P(EX_VAR(opline->op1.var))].pos =
+                               fe_ht->nInternalPointer = pos;
                        ZEND_VM_INC_OPCODE();
                        ZEND_VM_NEXT_OPCODE();
                } else {
@@ -5963,6 +5963,14 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
                                        if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
                                                zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var));
                                        }
+                               } else if (brk_opline->opcode == ZEND_FE_FREE) {
+                                       if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
+                                               zval *var = EX_VAR(brk_opline->op1.var);
+                                               if (Z_FE_ITER_P(var) != (uint32_t)-1) {
+                                                       zend_hash_iterator_del(Z_FE_ITER_P(var));
+                                               }
+                                               zval_ptr_dtor_nogc(var);
+                                       }
                                } else if (brk_opline->opcode == ZEND_END_SILENCE) {
                                        /* restore previous error_reporting value */
                                        if (!EG(error_reporting) && Z_LVAL_P(EX_VAR(brk_opline->op1.var)) != 0) {
index 362f450390f83fbee32f517f9547e7ec9d1e3b89..4244f5f750275adb457ceb694197a0abfd5ea1f1 100644 (file)
@@ -1347,6 +1347,14 @@ static int ZEND_FASTCALL  ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER
                                        if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
                                                zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var));
                                        }
+                               } else if (brk_opline->opcode == ZEND_FE_FREE) {
+                                       if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
+                                               zval *var = EX_VAR(brk_opline->op1.var);
+                                               if (Z_FE_ITER_P(var) != (uint32_t)-1) {
+                                                       zend_hash_iterator_del(Z_FE_ITER_P(var));
+                                               }
+                                               zval_ptr_dtor_nogc(var);
+                                       }
                                } else if (brk_opline->opcode == ZEND_END_SILENCE) {
                                        /* restore previous error_reporting value */
                                        if (!EG(error_reporting) && Z_LVAL_P(EX_VAR(brk_opline->op1.var)) != 0) {
@@ -1805,6 +1813,14 @@ static int ZEND_FASTCALL  ZEND_GOTO_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
                        zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var));
                }
+       } else if (brk_opline->opcode == ZEND_FE_FREE) {
+               if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
+                       zval *var = EX_VAR(brk_opline->op1.var);
+                       if (Z_FE_ITER_P(var) != (uint32_t)-1) {
+                               zend_hash_iterator_del(Z_FE_ITER_P(var));
+                       }
+                       zval_ptr_dtor_nogc(var);
+               }
        }
        ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op1));
 }
@@ -3175,8 +3191,7 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLE
                iter->index = -1; /* will be set to 0 before using next handler */
 
                ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
-               Z_FE_POS_P(EX_VAR(opline->result.var)) = INVALID_IDX;
-               ZVAL_PTR(EX_VAR((opline+2)->op1.var), NULL);
+               Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
 
                if (IS_CONST == IS_VAR) {
 
@@ -3215,6 +3230,7 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLE
                while (1) {
                        if (pos >= fe_ht->nNumUsed) {
 
+                               Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
                                ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
                        }
                        p = fe_ht->arData + pos;
@@ -3228,14 +3244,15 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLE
                        }
                        pos++;
                }
-               Z_FE_POS_P(EX_VAR(opline->result.var)) = fe_ht->nInternalPointer = pos;
-               ZVAL_PTR(EX_VAR((opline+2)->op1.var), fe_ht);
+               fe_ht->nInternalPointer = pos;
+               Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht);
 
                CHECK_EXCEPTION();
                ZEND_VM_NEXT_OPCODE();
        } else {
                zend_error(E_WARNING, "Invalid argument supplied for foreach()");
                ZVAL_UNDEF(EX_VAR(opline->result.var));
+               Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
                if (IS_CONST == IS_VAR) {
 
                } else {
@@ -9109,8 +9126,7 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_
                iter->index = -1; /* will be set to 0 before using next handler */
 
                ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
-               Z_FE_POS_P(EX_VAR(opline->result.var)) = INVALID_IDX;
-               ZVAL_PTR(EX_VAR((opline+2)->op1.var), NULL);
+               Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
 
                if (IS_TMP_VAR == IS_VAR) {
 
@@ -9149,6 +9165,7 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_
                while (1) {
                        if (pos >= fe_ht->nNumUsed) {
 
+                               Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
                                ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
                        }
                        p = fe_ht->arData + pos;
@@ -9162,14 +9179,15 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_
                        }
                        pos++;
                }
-               Z_FE_POS_P(EX_VAR(opline->result.var)) = fe_ht->nInternalPointer = pos;
-               ZVAL_PTR(EX_VAR((opline+2)->op1.var), fe_ht);
+               fe_ht->nInternalPointer = pos;
+               Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht);
 
                CHECK_EXCEPTION();
                ZEND_VM_NEXT_OPCODE();
        } else {
                zend_error(E_WARNING, "Invalid argument supplied for foreach()");
                ZVAL_UNDEF(EX_VAR(opline->result.var));
+               Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
                if (IS_TMP_VAR == IS_VAR) {
 
                } else {
@@ -11945,8 +11963,7 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_
                iter->index = -1; /* will be set to 0 before using next handler */
 
                ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
-               Z_FE_POS_P(EX_VAR(opline->result.var)) = INVALID_IDX;
-               ZVAL_PTR(EX_VAR((opline+2)->op1.var), NULL);
+               Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
 
                if (IS_VAR == IS_VAR) {
                        if (free_op1) {zval_ptr_dtor_nogc(free_op1);};
@@ -11985,6 +12002,7 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_
                while (1) {
                        if (pos >= fe_ht->nNumUsed) {
                                if (free_op1) {zval_ptr_dtor_nogc(free_op1);};
+                               Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
                                ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
                        }
                        p = fe_ht->arData + pos;
@@ -11998,8 +12016,8 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_
                        }
                        pos++;
                }
-               Z_FE_POS_P(EX_VAR(opline->result.var)) = fe_ht->nInternalPointer = pos;
-               ZVAL_PTR(EX_VAR((opline+2)->op1.var), fe_ht);
+               fe_ht->nInternalPointer = pos;
+               Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht);
 
                if (free_op1) {zval_ptr_dtor_nogc(free_op1);};
                CHECK_EXCEPTION();
@@ -12007,6 +12025,7 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_
        } else {
                zend_error(E_WARNING, "Invalid argument supplied for foreach()");
                ZVAL_UNDEF(EX_VAR(opline->result.var));
+               Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
                if (IS_VAR == IS_VAR) {
                        if (free_op1) {zval_ptr_dtor_nogc(free_op1);};
                } else {
@@ -12177,21 +12196,7 @@ static int ZEND_FASTCALL  ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_
        ZVAL_DEREF(array);
        if (EXPECTED(Z_TYPE_P(array) == IS_ARRAY)) {
                fe_ht = Z_ARRVAL_P(array);
-               pos = Z_FE_POS_P(EX_VAR(opline->op1.var));
-               if (UNEXPECTED(pos == INVALID_IDX)) {
-                       /* reached end of iteration */
-                       ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
-               } else {
-                       if (Z_PTR_P(EX_VAR((opline+1)->op1.var)) != fe_ht) {
-                               pos = fe_ht->nInternalPointer;
-                       }
-                       SEPARATE_ARRAY(array);
-                       fe_ht = Z_ARRVAL_P(array);
-                       Z_PTR_P(EX_VAR((opline+1)->op1.var)) = fe_ht;
-               }
-//???          if (pos != fe_ht->nInternalPointer) {
-//???                  //...
-//???          }
+               pos = zend_hash_iterator_pos(Z_FE_ITER_P(EX_VAR(opline->op1.var)), fe_ht);
                while (1) {
                        if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
                                /* reached end of iteration */
@@ -12235,7 +12240,8 @@ static int ZEND_FASTCALL  ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_
                                break;
                        }
                }
-               Z_FE_POS_P(EX_VAR(opline->op1.var)) = fe_ht->nInternalPointer = pos;
+               EG(ht_iterators)[Z_FE_ITER_P(EX_VAR(opline->op1.var))].pos =
+                       fe_ht->nInternalPointer = pos;
                ZEND_VM_INC_OPCODE();
                ZEND_VM_NEXT_OPCODE();
        } else if (EXPECTED(Z_TYPE_P(array) == IS_OBJECT)) {
@@ -12246,19 +12252,7 @@ static int ZEND_FASTCALL  ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_
                        zend_object *zobj = Z_OBJ_P(array);
 
                        fe_ht = Z_OBJPROP_P(array);
-                       pos = Z_FE_POS_P(EX_VAR(opline->op1.var));
-                       if (UNEXPECTED(pos == INVALID_IDX)) {
-                               /* reached end of iteration */
-                               ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
-                       } else {
-                               if (Z_PTR_P(EX_VAR((opline+1)->op1.var)) != fe_ht) {
-                                       pos = fe_ht->nInternalPointer;
-                               }
-                               Z_PTR_P(EX_VAR((opline+1)->op1.var)) = fe_ht;
-                       }
-//???                  if (pos != fe_ht->nInternalPointer) {
-//???
-//???                  }
+                       pos = zend_hash_iterator_pos(Z_FE_ITER_P(EX_VAR(opline->op1.var)), fe_ht);
                        while (1) {
                                if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
                                        /* reached end of iteration */
@@ -12316,7 +12310,8 @@ static int ZEND_FASTCALL  ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_
                                        break;
                                }
                        }
-                       Z_FE_POS_P(EX_VAR(opline->op1.var)) = fe_ht->nInternalPointer = pos;
+                       EG(ht_iterators)[Z_FE_ITER_P(EX_VAR(opline->op1.var))].pos =
+                               fe_ht->nInternalPointer = pos;
                        ZEND_VM_INC_OPCODE();
                        ZEND_VM_NEXT_OPCODE();
                } else {
@@ -24354,8 +24349,7 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_A
                iter->index = -1; /* will be set to 0 before using next handler */
 
                ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
-               Z_FE_POS_P(EX_VAR(opline->result.var)) = INVALID_IDX;
-               ZVAL_PTR(EX_VAR((opline+2)->op1.var), NULL);
+               Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
 
                if (IS_CV == IS_VAR) {
 
@@ -24394,6 +24388,7 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_A
                while (1) {
                        if (pos >= fe_ht->nNumUsed) {
 
+                               Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
                                ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
                        }
                        p = fe_ht->arData + pos;
@@ -24407,14 +24402,15 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_A
                        }
                        pos++;
                }
-               Z_FE_POS_P(EX_VAR(opline->result.var)) = fe_ht->nInternalPointer = pos;
-               ZVAL_PTR(EX_VAR((opline+2)->op1.var), fe_ht);
+               fe_ht->nInternalPointer = pos;
+               Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht);
 
                CHECK_EXCEPTION();
                ZEND_VM_NEXT_OPCODE();
        } else {
                zend_error(E_WARNING, "Invalid argument supplied for foreach()");
                ZVAL_UNDEF(EX_VAR(opline->result.var));
+               Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
                if (IS_CV == IS_VAR) {
 
                } else {
@@ -33144,6 +33140,21 @@ static int ZEND_FASTCALL  ZEND_FREE_SPEC_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS
        ZEND_VM_NEXT_OPCODE();
 }
 
+static int ZEND_FASTCALL  ZEND_FE_FREE_SPEC_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+       zval *var;
+       USE_OPLINE
+
+       SAVE_OPLINE();
+       var = EX_VAR(opline->op1.var);
+       if (Z_FE_ITER_P(var) != (uint32_t)-1) {
+               zend_hash_iterator_del(Z_FE_ITER_P(var));
+       }
+       zval_ptr_dtor_nogc(var);
+       CHECK_EXCEPTION();
+       ZEND_VM_NEXT_OPCODE();
+}
+
 static int ZEND_FASTCALL  ZEND_BOOL_SPEC_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
        USE_OPLINE
@@ -39719,16 +39730,16 @@ void zend_init_opcodes_handlers(void)
        ZEND_NULL_HANDLER,
        ZEND_NULL_HANDLER,
        ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
+       ZEND_FE_FREE_SPEC_TMPVAR_HANDLER,
+       ZEND_FE_FREE_SPEC_TMPVAR_HANDLER,
+       ZEND_FE_FREE_SPEC_TMPVAR_HANDLER,
+       ZEND_FE_FREE_SPEC_TMPVAR_HANDLER,
+       ZEND_FE_FREE_SPEC_TMPVAR_HANDLER,
+       ZEND_FE_FREE_SPEC_TMPVAR_HANDLER,
+       ZEND_FE_FREE_SPEC_TMPVAR_HANDLER,
+       ZEND_FE_FREE_SPEC_TMPVAR_HANDLER,
+       ZEND_FE_FREE_SPEC_TMPVAR_HANDLER,
+       ZEND_FE_FREE_SPEC_TMPVAR_HANDLER,
        ZEND_NULL_HANDLER,
        ZEND_NULL_HANDLER,
        ZEND_NULL_HANDLER,
index 295600c6fdfde00f698f13a94565a133909dc18b..d7c5db696685ae97d20d5d71264bf5328d4d87d4 100644 (file)
@@ -149,7 +149,7 @@ const char *zend_vm_opcodes_map[170] = {
        "ZEND_VERIFY_RETURN_TYPE",
        "ZEND_FE_RESET_RW",
        "ZEND_FE_FETCH_RW",
-       NULL,
+       "ZEND_FE_FREE",
        NULL,
        NULL,
        NULL,
index 9cb1679e9894a179661b227ea8c51c9530b0b7e0..aa4afbd984bbacb6f7a618ebd9f5c29d838a526a 100644 (file)
@@ -151,6 +151,7 @@ END_EXTERN_C()
 #define ZEND_VERIFY_RETURN_TYPE              124
 #define ZEND_FE_RESET_RW                     125
 #define ZEND_FE_FETCH_RW                     126
+#define ZEND_FE_FREE                         127
 #define ZEND_PRE_INC_OBJ                     132
 #define ZEND_PRE_DEC_OBJ                     133
 #define ZEND_POST_INC_OBJ                    134
index 3df0faa0ef571090f2dfaa4d0b23ba3ac939fb99..4db48944e170fa6606f26dc4c21bfd6765fdbd9f 100644 (file)
@@ -207,12 +207,15 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimiz
                for (i = 0; i< op_array->last_brk_cont; i++) {
                        if (op_array->brk_cont_array[i].start >= 0 &&
                            (op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FREE ||
+                            op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FE_FREE ||
                             op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_END_SILENCE)) {
                                int parent = op_array->brk_cont_array[i].parent;
 
                                while (parent >= 0 &&
                                       op_array->brk_cont_array[parent].start < 0 &&
-                                      op_array->opcodes[op_array->brk_cont_array[parent].brk].opcode != ZEND_FREE) {
+                                      (op_array->opcodes[op_array->brk_cont_array[parent].brk].opcode != ZEND_FREE ||
+                                       op_array->opcodes[op_array->brk_cont_array[parent].brk].opcode != ZEND_FE_FREE ||
+                                       op_array->opcodes[op_array->brk_cont_array[parent].brk].opcode != ZEND_END_SILENCE)) {
                                        parent = op_array->brk_cont_array[parent].parent;
                                }
                                op_array->brk_cont_array[i].parent = parent;
@@ -227,6 +230,7 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimiz
                        for (i = 0; i< op_array->last_brk_cont; i++) {
                                if (op_array->brk_cont_array[i].start >= 0 &&
                                    (op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FREE ||
+                                    op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FE_FREE ||
                                     op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_END_SILENCE)) {
                                        if (i != j) {
                                                op_array->brk_cont_array[j] = op_array->brk_cont_array[i];
index 7ff94ddae51cd09234c1301c485b6ee1f95f979a..dc93ce2f4c807112d91e0c21cd939050c0fb533b 100644 (file)
@@ -66,12 +66,6 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c
         if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) {
                        start_of_T[VAR_NUM(ZEND_RESULT(opline).var) - offset] = opline;
                }
-               /* special puprose variable to keep HashTable* on VM stack */
-               if (opline->opcode == ZEND_OP_DATA &&
-                   (opline-1)->opcode == ZEND_FE_FETCH_RW &&
-                   opline->op1_type == IS_TMP_VAR) {
-                       start_of_T[VAR_NUM(ZEND_OP1(opline).var) - offset] = opline;
-               }
                opline--;
        }
 
@@ -84,21 +78,13 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c
     while (opline >= end) {
                if ((ZEND_OP1_TYPE(opline) & (IS_VAR | IS_TMP_VAR))) {
 
-                       /* special puprose variable to keep HashPointer on VM stack */
-                       if (opline->opcode == ZEND_OP_DATA &&
-                           (opline-1)->opcode == ZEND_FE_FETCH_RW &&
-                               opline->op1_type == IS_TMP_VAR) {
-                               max++;
-                               ZEND_OP1(opline).var = NUM_VAR(max + offset);
-                       } else {
-                               currT = VAR_NUM(ZEND_OP1(opline).var) - offset;
-                               if (!valid_T[currT]) {
-                                       GET_AVAILABLE_T();
-                                       map_T[currT] = i;
-                                       valid_T[currT] = 1;
-                               }
-                               ZEND_OP1(opline).var = NUM_VAR(map_T[currT] + offset);
+                       currT = VAR_NUM(ZEND_OP1(opline).var) - offset;
+                       if (!valid_T[currT]) {
+                               GET_AVAILABLE_T();
+                               map_T[currT] = i;
+                               valid_T[currT] = 1;
                        }
+                       ZEND_OP1(opline).var = NUM_VAR(map_T[currT] + offset);
                }
 
                /* Skip OP_DATA */
index 5be1e30c9fc0666dd258dc83ef23dd34ed178ead..b5785924932f5c6d9240873e4c3a065b672f9ea7 100644 (file)
@@ -203,7 +203,9 @@ void zend_optimizer_pass2(zend_op_array *op_array)
                                                jmp_to = &op_array->brk_cont_array[array_offset];
                                                array_offset = jmp_to->parent;
                                                if (--nest_levels > 0) {
-                                                       if (op_array->opcodes[jmp_to->brk].opcode == ZEND_FREE) {
+                                                       if (op_array->opcodes[jmp_to->brk].opcode == ZEND_FREE ||
+                                                           op_array->opcodes[jmp_to->brk].opcode == ZEND_FE_FREE ||
+                                                           op_array->opcodes[jmp_to->brk].opcode == ZEND_END_SILENCE) {
                                                                dont_optimize = 1;
                                                                break;
                                                        }
index 966ea0f1f69de13359b64b89639031c9b4868be1..397bb88f0b99bc4a1d40c7218257dfdcf5b1e07c 100644 (file)
@@ -2203,6 +2203,9 @@ PHP_FUNCTION(array_shift)
                                q->key = NULL;
                                ZVAL_COPY_VALUE(&q->val, &p->val);
                                ZVAL_UNDEF(&p->val);
+                               if (idx == Z_ARRVAL_P(stack)->nInternalPointer) {
+                                       zend_hash_iterators_update(Z_ARRVAL_P(stack), k);
+                               }
                        }
                        k++;
                }
@@ -2265,9 +2268,14 @@ PHP_FUNCTION(array_unshift)
                }
        } ZEND_HASH_FOREACH_END();
 
+       new_hash.nInternalPointer = Z_ARRVAL_P(stack)->nInternalPointer;
+       new_hash.u.v.nIteratorsCount = Z_ARRVAL_P(stack)->u.v.nIteratorsCount;
+       Z_ARRVAL_P(stack)->u.v.nIteratorsCount = 0;
        Z_ARRVAL_P(stack)->pDestructor = NULL;
        zend_hash_destroy(Z_ARRVAL_P(stack));
        *Z_ARRVAL_P(stack) = new_hash;
+       zend_hash_iterators_update(Z_ARRVAL_P(stack), 0);
+       zend_hash_internal_pointer_reset(Z_ARRVAL_P(stack));
 
        /* Clean up and return the number of elements in the stack */
        RETVAL_LONG(zend_hash_num_elements(Z_ARRVAL_P(stack)));
index b0c5e8dcf51c195119a714bf47331cafade04520..10f43f39986535435b133fdf6d659b4348f87a76 100644 (file)
@@ -1,7 +1,5 @@
 --TEST--\r
 Directly modifying an unreferenced array when foreach'ing over it while using &$value syntax.\r
---XFAIL--\r
-Needs major foreach changes to get sane behavior\r
 --FILE--\r
 <?php\r
 \r
@@ -70,7 +68,7 @@ withRefValue(3, $transform);
 withRefValue(4, $transform);\r
 \r
 ?>\r
---EXPECTF--\r
+--EXPECT--\r
 \r
 Popping elements off end of an unreferenced array, using &$value.\r
 ---( Array with 1 element(s): )---\r
@@ -95,9 +93,10 @@ array(2) {
 }\r
 --> Do loop:\r
      iteration 0:  $k=0; $v=v.0\r
-     iteration 1:  $k=0; $v=v.0\r
 --> State of array after loop:\r
-array(0) {\r
+array(1) {\r
+  [0]=>\r
+  &string(3) "v.0"\r
 }\r
 \r
 ---( Array with 3 element(s): )---\r
@@ -134,10 +133,12 @@ array(4) {
 --> Do loop:\r
      iteration 0:  $k=0; $v=v.0\r
      iteration 1:  $k=1; $v=v.1\r
-     iteration 2:  $k=0; $v=v.0\r
-     iteration 3:  $k=0; $v=v.0\r
 --> State of array after loop:\r
-array(0) {\r
+array(2) {\r
+  [0]=>\r
+  string(3) "v.0"\r
+  [1]=>\r
+  &string(3) "v.1"\r
 }\r
 \r
 \r
@@ -289,12 +290,28 @@ array(1) {
 }\r
 --> Do loop:\r
      iteration 0:  $k=0; $v=v.0\r
+     iteration 1:  $k=1; $v=new.0\r
+     iteration 2:  $k=2; $v=new.1\r
+     iteration 3:  $k=3; $v=new.2\r
+     iteration 4:  $k=4; $v=new.3\r
+     iteration 5:  $k=5; $v=new.4\r
+  ** Stuck in a loop! **\r
 --> State of array after loop:\r
-array(2) {\r
+array(7) {\r
   [0]=>\r
-  &string(3) "v.0"\r
+  string(3) "v.0"\r
   [1]=>\r
   string(5) "new.0"\r
+  [2]=>\r
+  string(5) "new.1"\r
+  [3]=>\r
+  string(5) "new.2"\r
+  [4]=>\r
+  string(5) "new.3"\r
+  [5]=>\r
+  &string(5) "new.4"\r
+  [6]=>\r
+  string(5) "new.5"\r
 }\r
 \r
 ---( Array with 2 element(s): )---\r
@@ -428,12 +445,28 @@ array(1) {
 }\r
 --> Do loop:\r
      iteration 0:  $k=0; $v=v.0\r
+     iteration 1:  $k=0; $v=new.0\r
+     iteration 2:  $k=0; $v=new.1\r
+     iteration 3:  $k=0; $v=new.2\r
+     iteration 4:  $k=0; $v=new.3\r
+     iteration 5:  $k=0; $v=new.4\r
+  ** Stuck in a loop! **\r
 --> State of array after loop:\r
-array(2) {\r
+array(7) {\r
   [0]=>\r
-  string(5) "new.0"\r
+  string(5) "new.5"\r
   [1]=>\r
-  &string(3) "v.0"\r
+  &string(5) "new.4"\r
+  [2]=>\r
+  string(5) "new.3"\r
+  [3]=>\r
+  string(5) "new.2"\r
+  [4]=>\r
+  string(5) "new.1"\r
+  [5]=>\r
+  string(5) "new.0"\r
+  [6]=>\r
+  string(3) "v.0"\r
 }\r
 \r
 ---( Array with 2 element(s): )---\r
index 5b12a2b0c269f317c2c3805794ccf14db49a59e2..a56249ee0b4081b197a1c35950f9fcf52b66adf9 100644 (file)
@@ -1,7 +1,5 @@
 --TEST--\r
 Directly modifying a REFERENCED array when foreach'ing over it while using &$value syntax.\r
---XFAIL--\r
-Needs major foreach changes to get sane behavior\r
 --FILE--\r
 <?php\r
 \r
@@ -72,7 +70,7 @@ withRefValue(3, $transform);
 withRefValue(4, $transform);\r
 \r
 ?>\r
---EXPECTF--\r
+--EXPECT--\r
 \r
 Popping elements off end of a referenced array, using &$value\r
 ---( Array with 1 element(s): )---\r
@@ -97,9 +95,10 @@ array(2) {
 }\r
 --> Do loop:\r
      iteration 0:  $k=0; $v=v.0\r
-     iteration 1:  $k=0; $v=v.0\r
 --> State of array after loop:\r
-array(0) {\r
+array(1) {\r
+  [0]=>\r
+  &string(3) "v.0"\r
 }\r
 \r
 ---( Array with 3 element(s): )---\r
@@ -136,10 +135,12 @@ array(4) {
 --> Do loop:\r
      iteration 0:  $k=0; $v=v.0\r
      iteration 1:  $k=1; $v=v.1\r
-     iteration 2:  $k=0; $v=v.0\r
-     iteration 3:  $k=0; $v=v.0\r
 --> State of array after loop:\r
-array(0) {\r
+array(2) {\r
+  [0]=>\r
+  string(3) "v.0"\r
+  [1]=>\r
+  &string(3) "v.1"\r
 }\r
 \r
 \r
@@ -291,12 +292,28 @@ array(1) {
 }\r
 --> Do loop:\r
      iteration 0:  $k=0; $v=v.0\r
+     iteration 1:  $k=1; $v=new.0\r
+     iteration 2:  $k=2; $v=new.1\r
+     iteration 3:  $k=3; $v=new.2\r
+     iteration 4:  $k=4; $v=new.3\r
+     iteration 5:  $k=5; $v=new.4\r
+  ** Stuck in a loop! **\r
 --> State of array after loop:\r
-array(2) {\r
+array(7) {\r
   [0]=>\r
-  &string(3) "v.0"\r
+  string(3) "v.0"\r
   [1]=>\r
   string(5) "new.0"\r
+  [2]=>\r
+  string(5) "new.1"\r
+  [3]=>\r
+  string(5) "new.2"\r
+  [4]=>\r
+  string(5) "new.3"\r
+  [5]=>\r
+  &string(5) "new.4"\r
+  [6]=>\r
+  string(5) "new.5"\r
 }\r
 \r
 ---( Array with 2 element(s): )---\r
@@ -430,12 +447,28 @@ array(1) {
 }\r
 --> Do loop:\r
      iteration 0:  $k=0; $v=v.0\r
+     iteration 1:  $k=0; $v=new.0\r
+     iteration 2:  $k=0; $v=new.1\r
+     iteration 3:  $k=0; $v=new.2\r
+     iteration 4:  $k=0; $v=new.3\r
+     iteration 5:  $k=0; $v=new.4\r
+  ** Stuck in a loop! **\r
 --> State of array after loop:\r
-array(2) {\r
+array(7) {\r
   [0]=>\r
-  string(5) "new.0"\r
+  string(5) "new.5"\r
   [1]=>\r
-  &string(3) "v.0"\r
+  &string(5) "new.4"\r
+  [2]=>\r
+  string(5) "new.3"\r
+  [3]=>\r
+  string(5) "new.2"\r
+  [4]=>\r
+  string(5) "new.1"\r
+  [5]=>\r
+  string(5) "new.0"\r
+  [6]=>\r
+  string(3) "v.0"\r
 }\r
 \r
 ---( Array with 2 element(s): )---\r