]> granicus.if.org Git - php/commitdiff
Implement consistent behavior for foreach by value over plain object
authorDmitry Stogov <dmitry@zend.com>
Fri, 30 Jan 2015 06:49:35 +0000 (09:49 +0300)
committerDmitry Stogov <dmitry@zend.com>
Fri, 30 Jan 2015 06:49:35 +0000 (09:49 +0300)
Zend/tests/foreach_010.phpt [new file with mode: 0644]
Zend/zend_compile.c
Zend/zend_execute.c
Zend/zend_generators.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

diff --git a/Zend/tests/foreach_010.phpt b/Zend/tests/foreach_010.phpt
new file mode 100644 (file)
index 0000000..6ba7e7e
--- /dev/null
@@ -0,0 +1,40 @@
+--TEST--
+Nested foreach by value over object and object modification with resize
+--FILE--
+<?php
+$o = (object)['a'=>0, 'b'=>1, 'c'=>2, 'd'=>3, 'e'=>4, 'f'=>5, 'g'=>6, 'h'=>7];
+unset($o->a, $o->b, $o->c, $o->d);
+foreach ($o as $v1) {
+       foreach ($o as $v2) {
+               echo "$v1-$v2\n";
+               if ($v1 == 5 && $v2 == 6) {
+                       $o->i = 8;
+               }       
+       }
+}
+?>
+--EXPECT--
+4-4
+4-5
+4-6
+4-7
+5-4
+5-5
+5-6
+5-7
+5-8
+6-4
+6-5
+6-6
+6-7
+6-8
+7-4
+7-5
+7-6
+7-7
+7-8
+8-4
+8-5
+8-6
+8-7
+8-8
index 080b31562ac308006f53d95e0bc63f89b5bf6284..79293971e8f5dc19a6459722334e473cea8b449e 100644 (file)
@@ -3398,7 +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;
+       reset_node.flag = 1; /* generate FE_FREE */
        zend_stack_push(&CG(loop_var_stack), &reset_node);
 
        opnum_fetch = get_next_op_number(CG(active_op_array));
index d59aef1d1b16bc19e9100a0adb1b94e050bb5ab1..1a81c298a8face4903fa80fe72a901fef324684f 100644 (file)
@@ -1587,7 +1587,7 @@ static inline zend_brk_cont_element* zend_brk_cont(int nest_levels, int array_of
                        } 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) {
+                                       if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
                                                zend_hash_iterator_del(Z_FE_ITER_P(var));
                                        }
                                        zval_ptr_dtor_nogc(var);
index 1f25d07ea9dd06d4f0822423907cd88466b2f11c..971d4e7bc8c6ce91cdab8cb6e2cf5d14a18b14f5 100644 (file)
@@ -62,7 +62,7 @@ static void zend_generator_cleanup_unfinished_execution(zend_generator *generato
                                        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) {
+                                       if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
                                                zend_hash_iterator_del(Z_FE_ITER_P(var));
                                        }
                                        zval_ptr_dtor_nogc(var);
index 245bc0b68a1a47bbed5f23320f4b0658e3ed566e..064c756c6e23a043cfe0565b1b8c1071afc0b30c 100644 (file)
@@ -2145,7 +2145,7 @@ ZEND_VM_HANDLER(127, ZEND_FE_FREE, TMPVAR, ANY)
 
        SAVE_OPLINE();
        var = EX_VAR(opline->op1.var);
-       if (Z_FE_ITER_P(var) != (uint32_t)-1) {
+       if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
                zend_hash_iterator_del(Z_FE_ITER_P(var));
        }
        zval_ptr_dtor_nogc(var);
@@ -3839,7 +3839,7 @@ ZEND_VM_HANDLER(100, ZEND_GOTO, ANY, CONST)
        } 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) {
+                       if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
                                zend_hash_iterator_del(Z_FE_ITER_P(var));
                        }
                        zval_ptr_dtor_nogc(var);
@@ -4647,70 +4647,105 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET_R, CONST|TMP|VAR|CV, ANY)
 {
        USE_OPLINE
        zend_free_op free_op1;
-       zval *array_ptr;
+       zval *array_ptr, *result;
        HashTable *fe_ht;
 
        SAVE_OPLINE();
 
        array_ptr = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R);
-       if (OP1_TYPE != IS_CONST &&
-           Z_TYPE_P(array_ptr) == IS_OBJECT && Z_OBJCE_P(array_ptr)->get_iterator) {
-               zend_class_entry *ce = Z_OBJCE_P(array_ptr);
-               zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 0);
-               zend_bool is_empty;
+       if (EXPECTED(Z_TYPE_P(array_ptr) == IS_ARRAY)) {
+               result = EX_VAR(opline->result.var);
+               ZVAL_COPY_VALUE(result, array_ptr);
+               if (OP1_TYPE != IS_TMP_VAR && Z_OPT_REFCOUNTED_P(result)) {
+                       Z_ADDREF_P(array_ptr);
+               }
+               Z_FE_POS_P(result) = 0;
 
-               if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
-                       FREE_OP1();
-                       if (!EG(exception)) {
-                               zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+               FREE_OP1_IF_VAR();
+               CHECK_EXCEPTION();
+               ZEND_VM_NEXT_OPCODE();
+       } else if (OP1_TYPE != IS_CONST && EXPECTED(Z_TYPE_P(array_ptr) == IS_OBJECT)) {
+               if (!Z_OBJCE_P(array_ptr)->get_iterator) {
+                       HashPosition pos = 0;
+                       Bucket *p;
+
+                       result = EX_VAR(opline->result.var);
+                       ZVAL_COPY_VALUE(result, array_ptr);
+                       if (OP1_TYPE != IS_TMP_VAR) {
+                               Z_ADDREF_P(array_ptr);
+                       }
+                       fe_ht = Z_OBJPROP_P(array_ptr);
+                       pos = 0;
+                       while (1) {
+                               if (pos >= fe_ht->nNumUsed) {
+                                       FREE_OP1_IF_VAR();
+                                       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;
+                               if ((Z_TYPE(p->val) != IS_UNDEF &&
+                                    (Z_TYPE(p->val) != IS_INDIRECT ||
+                                     Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
+                                   (!p->key ||
+                                    zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
+                                       break;
+                               }
+                               pos++;
                        }
-                       zend_throw_exception_internal(NULL);
-                       HANDLE_EXCEPTION();
-               }
+                       fe_ht->nInternalPointer = pos;
+                       Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht);
+
+                       FREE_OP1_IF_VAR();
+                       CHECK_EXCEPTION();
+                       ZEND_VM_NEXT_OPCODE();
+               } else {
+                       zend_class_entry *ce = Z_OBJCE_P(array_ptr);
+                       zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 0);
+                       zend_bool is_empty;
+
+                       if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
+                               FREE_OP1();
+                               if (!EG(exception)) {
+                                       zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+                               }
+                               zend_throw_exception_internal(NULL);
+                               HANDLE_EXCEPTION();
+                       }
+
+                       iter->index = 0;
+                       if (iter->funcs->rewind) {
+                               iter->funcs->rewind(iter);
+                               if (UNEXPECTED(EG(exception) != NULL)) {
+                                       OBJ_RELEASE(&iter->std);
+                                       FREE_OP1();
+                                       HANDLE_EXCEPTION();
+                               }
+                       }
+
+                       is_empty = iter->funcs->valid(iter) != SUCCESS;
 
-               iter->index = 0;
-               if (iter->funcs->rewind) {
-                       iter->funcs->rewind(iter);
                        if (UNEXPECTED(EG(exception) != NULL)) {
                                OBJ_RELEASE(&iter->std);
                                FREE_OP1();
                                HANDLE_EXCEPTION();
                        }
-               }
-               
-               is_empty = iter->funcs->valid(iter) != SUCCESS;
-                               
-               if (UNEXPECTED(EG(exception) != NULL)) {
-                       OBJ_RELEASE(&iter->std);
-                       FREE_OP1();
-                       HANDLE_EXCEPTION();
-               }
-               iter->index = -1; /* will be set to 0 before using next handler */
+                       iter->index = -1; /* will be set to 0 before using next handler */
 
-               ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
+                       ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
+                       Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
 
-               FREE_OP1();
-               if (is_empty) {
-                       ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
-               } else {
-                       CHECK_EXCEPTION();
-                       ZEND_VM_NEXT_OPCODE();
-               }
-       } else if ((fe_ht = HASH_OF(array_ptr)) != NULL) {
-               zval *result = EX_VAR(opline->result.var);
-
-               ZVAL_COPY_VALUE(result, array_ptr);
-               if (OP1_TYPE != IS_TMP_VAR && Z_OPT_REFCOUNTED_P(result)) {
-                       Z_ADDREF_P(array_ptr);
+                       FREE_OP1();
+                       if (is_empty) {
+                               ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+                       } else {
+                               CHECK_EXCEPTION();
+                               ZEND_VM_NEXT_OPCODE();
+                       }
                }
-               Z_FE_POS_P(result) = 0;
-
-               FREE_OP1_IF_VAR();
-               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;
                FREE_OP1();
                ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
        }
@@ -4722,6 +4757,8 @@ ZEND_VM_HANDLER(125, ZEND_FE_RESET_RW, CONST|TMP|VAR|CV, ANY)
        zend_free_op free_op1;
        zval *array_ptr, *array_ref;
        HashTable *fe_ht;
+       HashPosition pos = 0;
+       Bucket *p;
 
        SAVE_OPLINE();
 
@@ -4734,70 +4771,7 @@ ZEND_VM_HANDLER(125, ZEND_FE_RESET_RW, CONST|TMP|VAR|CV, ANY)
                array_ref = array_ptr = GET_OP1_ZVAL_PTR(BP_VAR_R);
        }
 
-       if (OP1_TYPE != IS_CONST &&
-           Z_TYPE_P(array_ptr) == IS_OBJECT && Z_OBJCE_P(array_ptr)->get_iterator) {
-               zend_class_entry *ce = Z_OBJCE_P(array_ptr);
-               zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 1);
-               zend_bool is_empty;
-
-               if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
-                       if (OP1_TYPE == IS_VAR) {
-                               FREE_OP1_VAR_PTR();
-                       } else {
-                               FREE_OP1();
-                       }
-                       if (!EG(exception)) {
-                               zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
-                       }
-                       zend_throw_exception_internal(NULL);
-                       HANDLE_EXCEPTION();
-               }
-
-               iter->index = 0;
-               if (iter->funcs->rewind) {
-                       iter->funcs->rewind(iter);
-                       if (UNEXPECTED(EG(exception) != NULL)) {
-                               OBJ_RELEASE(&iter->std);
-                               if (OP1_TYPE == IS_VAR) {
-                                       FREE_OP1_VAR_PTR();
-                               } else {
-                                       FREE_OP1();
-                               }
-                               HANDLE_EXCEPTION();
-                       }
-               }
-               
-               is_empty = iter->funcs->valid(iter) != SUCCESS;
-                               
-               if (UNEXPECTED(EG(exception) != NULL)) {
-                       OBJ_RELEASE(&iter->std);
-                       if (OP1_TYPE == IS_VAR) {
-                               FREE_OP1_VAR_PTR();
-                       } else {
-                               FREE_OP1();
-                       }
-                       HANDLE_EXCEPTION();
-               }
-               iter->index = -1; /* will be set to 0 before using next handler */
-
-               ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
-               Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
-
-               if (OP1_TYPE == IS_VAR) {
-                       FREE_OP1_VAR_PTR();
-               } else {
-                       FREE_OP1();
-               }
-               if (is_empty) {
-                       ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
-               } else {
-                       CHECK_EXCEPTION();
-                       ZEND_VM_NEXT_OPCODE();
-               }
-       } else if ((fe_ht = HASH_OF(array_ptr)) != NULL) {
-               HashPosition pos = 0;
-               Bucket *p;
-
+       if (EXPECTED(Z_TYPE_P(array_ptr) == IS_ARRAY)) {
                if (OP1_TYPE == IS_VAR || OP1_TYPE == IS_CV) {
                        if (array_ptr == array_ref) {
                                ZVAL_NEW_REF(array_ref, array_ref);
@@ -4809,14 +4783,12 @@ ZEND_VM_HANDLER(125, ZEND_FE_RESET_RW, CONST|TMP|VAR|CV, ANY)
                        array_ptr = EX_VAR(opline->result.var);
                        ZVAL_COPY_VALUE(array_ptr, array_ref);
                }
-               if (Z_TYPE_P(array_ptr) == IS_ARRAY) {
-                       if (OP1_TYPE == IS_CONST) {
-                               zval_copy_ctor_func(array_ptr);
-                       } else {
-                               SEPARATE_ARRAY(array_ptr);
-                       }
-                       fe_ht = Z_ARRVAL_P(array_ptr);
+               if (OP1_TYPE == IS_CONST) {
+                       zval_copy_ctor_func(array_ptr);
+               } else {
+                       SEPARATE_ARRAY(array_ptr);
                }
+               fe_ht = Z_ARRVAL_P(array_ptr);
                while (1) {
                        if (pos >= fe_ht->nNumUsed) {
                                FREE_OP1_VAR_PTR();
@@ -4824,12 +4796,9 @@ ZEND_VM_HANDLER(125, ZEND_FE_RESET_RW, CONST|TMP|VAR|CV, ANY)
                                ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
                        }
                        p = fe_ht->arData + pos;
-                       if ((Z_TYPE(p->val) != IS_UNDEF &&
-                            (Z_TYPE(p->val) != IS_INDIRECT ||
-                             Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
-                           (Z_TYPE_P(array_ptr) != IS_OBJECT ||
-                            !p->key ||
-                            zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
+                       if (Z_TYPE(p->val) != IS_UNDEF &&
+                           (Z_TYPE(p->val) != IS_INDIRECT ||
+                            Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) {
                                break;
                        }
                        pos++;
@@ -4840,6 +4809,102 @@ ZEND_VM_HANDLER(125, ZEND_FE_RESET_RW, CONST|TMP|VAR|CV, ANY)
                FREE_OP1_VAR_PTR();
                CHECK_EXCEPTION();
                ZEND_VM_NEXT_OPCODE();
+       } else if (OP1_TYPE != IS_CONST && EXPECTED(Z_TYPE_P(array_ptr) == IS_OBJECT)) {
+               if (!Z_OBJCE_P(array_ptr)->get_iterator) {
+                       if (OP1_TYPE == IS_VAR || OP1_TYPE == IS_CV) {
+                               if (array_ptr == array_ref) {
+                                       ZVAL_NEW_REF(array_ref, array_ref);
+                                       array_ptr = Z_REFVAL_P(array_ref);
+                               }
+                               Z_ADDREF_P(array_ref);
+                               ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref);
+                       } else {
+                               array_ptr = EX_VAR(opline->result.var);
+                               ZVAL_COPY_VALUE(array_ptr, array_ref);
+                       }
+                       fe_ht = Z_OBJPROP_P(array_ptr);
+                       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;
+                               if ((Z_TYPE(p->val) != IS_UNDEF &&
+                                    (Z_TYPE(p->val) != IS_INDIRECT ||
+                                     Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
+                                   (!p->key ||
+                                    zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
+                                       break;
+                               }
+                               pos++;
+                       }
+                       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();
+                       ZEND_VM_NEXT_OPCODE();
+               } else {
+                       zend_class_entry *ce = Z_OBJCE_P(array_ptr);
+                       zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 1);
+                       zend_bool is_empty;
+
+                       if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
+                               if (OP1_TYPE == IS_VAR) {
+                                       FREE_OP1_VAR_PTR();
+                               } else {
+                                       FREE_OP1();
+                               }
+                               if (!EG(exception)) {
+                                       zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+                               }
+                               zend_throw_exception_internal(NULL);
+                               HANDLE_EXCEPTION();
+                       }
+
+                       iter->index = 0;
+                       if (iter->funcs->rewind) {
+                               iter->funcs->rewind(iter);
+                               if (UNEXPECTED(EG(exception) != NULL)) {
+                                       OBJ_RELEASE(&iter->std);
+                                       if (OP1_TYPE == IS_VAR) {
+                                               FREE_OP1_VAR_PTR();
+                                       } else {
+                                               FREE_OP1();
+                                       }
+                                       HANDLE_EXCEPTION();
+                               }
+                       }
+
+                       is_empty = iter->funcs->valid(iter) != SUCCESS;
+
+                       if (UNEXPECTED(EG(exception) != NULL)) {
+                               OBJ_RELEASE(&iter->std);
+                               if (OP1_TYPE == IS_VAR) {
+                                       FREE_OP1_VAR_PTR();
+                               } else {
+                                       FREE_OP1();
+                               }
+                               HANDLE_EXCEPTION();
+                       }
+                       iter->index = -1; /* will be set to 0 before using next handler */
+
+                       ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
+                       Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+
+                       if (OP1_TYPE == IS_VAR) {
+                               FREE_OP1_VAR_PTR();
+                       } else {
+                               FREE_OP1();
+                       }
+                       if (is_empty) {
+                               ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+                       } else {
+                               CHECK_EXCEPTION();
+                               ZEND_VM_NEXT_OPCODE();
+                       }
+               }
        } else {
                zend_error(E_WARNING, "Invalid argument supplied for foreach()");
                ZVAL_UNDEF(EX_VAR(opline->result.var));
@@ -4906,7 +4971,7 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH_R, 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));
+                       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 */
@@ -4945,7 +5010,24 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH_R, VAR, ANY)
                                }
                        }
                        ZVAL_COPY(EX_VAR(opline->result.var), value);
-                       Z_FE_POS_P(EX_VAR(opline->op1.var)) = pos + 1;
+                       while (1) {
+                               pos++;
+                               if (pos >= fe_ht->nNumUsed) {
+                                       pos = INVALID_IDX;
+                                       break;
+                               }
+                               p = fe_ht->arData + pos;
+                               if ((Z_TYPE(p->val) != IS_UNDEF &&
+                                    (Z_TYPE(p->val) != IS_INDIRECT ||
+                                     Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
+                                   (Z_TYPE_P(array) != IS_OBJECT ||
+                                    !p->key ||
+                                    zend_check_property_access(Z_OBJ_P(array), p->key) == SUCCESS)) {
+                                       break;
+                               }
+                       }
+                       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 {
@@ -5966,7 +6048,7 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
                                } 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) {
+                                               if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
                                                        zend_hash_iterator_del(Z_FE_ITER_P(var));
                                                }
                                                zval_ptr_dtor_nogc(var);
index 4244f5f750275adb457ceb694197a0abfd5ea1f1..8ae97d2bf807d38344db55622320cdc2878681f6 100644 (file)
@@ -1350,7 +1350,7 @@ static int ZEND_FASTCALL  ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER
                                } 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) {
+                                               if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
                                                        zend_hash_iterator_del(Z_FE_ITER_P(var));
                                                }
                                                zval_ptr_dtor_nogc(var);
@@ -1816,7 +1816,7 @@ static int ZEND_FASTCALL  ZEND_GOTO_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        } 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) {
+                       if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
                                zend_hash_iterator_del(Z_FE_ITER_P(var));
                        }
                        zval_ptr_dtor_nogc(var);
@@ -3059,68 +3059,102 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_R_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER
 {
        USE_OPLINE
 
-       zval *array_ptr;
+       zval *array_ptr, *result;
        HashTable *fe_ht;
 
        SAVE_OPLINE();
 
        array_ptr = EX_CONSTANT(opline->op1);
-       if (IS_CONST != IS_CONST &&
-           Z_TYPE_P(array_ptr) == IS_OBJECT && Z_OBJCE_P(array_ptr)->get_iterator) {
-               zend_class_entry *ce = Z_OBJCE_P(array_ptr);
-               zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 0);
-               zend_bool is_empty;
+       if (EXPECTED(Z_TYPE_P(array_ptr) == IS_ARRAY)) {
+               result = EX_VAR(opline->result.var);
+               ZVAL_COPY_VALUE(result, array_ptr);
+               if (IS_CONST != IS_TMP_VAR && Z_OPT_REFCOUNTED_P(result)) {
+                       Z_ADDREF_P(array_ptr);
+               }
+               Z_FE_POS_P(result) = 0;
 
-               if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
+               CHECK_EXCEPTION();
+               ZEND_VM_NEXT_OPCODE();
+       } else if (IS_CONST != IS_CONST && EXPECTED(Z_TYPE_P(array_ptr) == IS_OBJECT)) {
+               if (!Z_OBJCE_P(array_ptr)->get_iterator) {
+                       HashPosition pos = 0;
+                       Bucket *p;
+
+                       result = EX_VAR(opline->result.var);
+                       ZVAL_COPY_VALUE(result, array_ptr);
+                       if (IS_CONST != IS_TMP_VAR) {
+                               Z_ADDREF_P(array_ptr);
+                       }
+                       fe_ht = Z_OBJPROP_P(array_ptr);
+                       pos = 0;
+                       while (1) {
+                               if (pos >= fe_ht->nNumUsed) {
 
-                       if (!EG(exception)) {
-                               zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+                                       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;
+                               if ((Z_TYPE(p->val) != IS_UNDEF &&
+                                    (Z_TYPE(p->val) != IS_INDIRECT ||
+                                     Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
+                                   (!p->key ||
+                                    zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
+                                       break;
+                               }
+                               pos++;
                        }
-                       zend_throw_exception_internal(NULL);
-                       HANDLE_EXCEPTION();
-               }
+                       fe_ht->nInternalPointer = pos;
+                       Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht);
 
-               iter->index = 0;
-               if (iter->funcs->rewind) {
-                       iter->funcs->rewind(iter);
-                       if (UNEXPECTED(EG(exception) != NULL)) {
-                               OBJ_RELEASE(&iter->std);
+                       CHECK_EXCEPTION();
+                       ZEND_VM_NEXT_OPCODE();
+               } else {
+                       zend_class_entry *ce = Z_OBJCE_P(array_ptr);
+                       zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 0);
+                       zend_bool is_empty;
+
+                       if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
 
+                               if (!EG(exception)) {
+                                       zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+                               }
+                               zend_throw_exception_internal(NULL);
                                HANDLE_EXCEPTION();
                        }
-               }
 
-               is_empty = iter->funcs->valid(iter) != SUCCESS;
+                       iter->index = 0;
+                       if (iter->funcs->rewind) {
+                               iter->funcs->rewind(iter);
+                               if (UNEXPECTED(EG(exception) != NULL)) {
+                                       OBJ_RELEASE(&iter->std);
 
-               if (UNEXPECTED(EG(exception) != NULL)) {
-                       OBJ_RELEASE(&iter->std);
+                                       HANDLE_EXCEPTION();
+                               }
+                       }
 
-                       HANDLE_EXCEPTION();
-               }
-               iter->index = -1; /* will be set to 0 before using next handler */
+                       is_empty = iter->funcs->valid(iter) != SUCCESS;
 
-               ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
+                       if (UNEXPECTED(EG(exception) != NULL)) {
+                               OBJ_RELEASE(&iter->std);
 
-               if (is_empty) {
-                       ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
-               } else {
-                       CHECK_EXCEPTION();
-                       ZEND_VM_NEXT_OPCODE();
-               }
-       } else if ((fe_ht = HASH_OF(array_ptr)) != NULL) {
-               zval *result = EX_VAR(opline->result.var);
+                               HANDLE_EXCEPTION();
+                       }
+                       iter->index = -1; /* will be set to 0 before using next handler */
 
-               ZVAL_COPY_VALUE(result, array_ptr);
-               if (IS_CONST != IS_TMP_VAR && Z_OPT_REFCOUNTED_P(result)) {
-                       Z_ADDREF_P(array_ptr);
-               }
-               Z_FE_POS_P(result) = 0;
+                       ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
+                       Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
 
-               CHECK_EXCEPTION();
-               ZEND_VM_NEXT_OPCODE();
+                       if (is_empty) {
+                               ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+                       } else {
+                               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;
 
                ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
        }
@@ -3132,6 +3166,8 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLE
 
        zval *array_ptr, *array_ref;
        HashTable *fe_ht;
+       HashPosition pos = 0;
+       Bucket *p;
 
        SAVE_OPLINE();
 
@@ -3144,70 +3180,7 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLE
                array_ref = array_ptr = EX_CONSTANT(opline->op1);
        }
 
-       if (IS_CONST != IS_CONST &&
-           Z_TYPE_P(array_ptr) == IS_OBJECT && Z_OBJCE_P(array_ptr)->get_iterator) {
-               zend_class_entry *ce = Z_OBJCE_P(array_ptr);
-               zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 1);
-               zend_bool is_empty;
-
-               if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
-                       if (IS_CONST == IS_VAR) {
-
-                       } else {
-
-                       }
-                       if (!EG(exception)) {
-                               zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
-                       }
-                       zend_throw_exception_internal(NULL);
-                       HANDLE_EXCEPTION();
-               }
-
-               iter->index = 0;
-               if (iter->funcs->rewind) {
-                       iter->funcs->rewind(iter);
-                       if (UNEXPECTED(EG(exception) != NULL)) {
-                               OBJ_RELEASE(&iter->std);
-                               if (IS_CONST == IS_VAR) {
-
-                               } else {
-
-                               }
-                               HANDLE_EXCEPTION();
-                       }
-               }
-
-               is_empty = iter->funcs->valid(iter) != SUCCESS;
-
-               if (UNEXPECTED(EG(exception) != NULL)) {
-                       OBJ_RELEASE(&iter->std);
-                       if (IS_CONST == IS_VAR) {
-
-                       } else {
-
-                       }
-                       HANDLE_EXCEPTION();
-               }
-               iter->index = -1; /* will be set to 0 before using next handler */
-
-               ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
-               Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
-
-               if (IS_CONST == IS_VAR) {
-
-               } else {
-
-               }
-               if (is_empty) {
-                       ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
-               } else {
-                       CHECK_EXCEPTION();
-                       ZEND_VM_NEXT_OPCODE();
-               }
-       } else if ((fe_ht = HASH_OF(array_ptr)) != NULL) {
-               HashPosition pos = 0;
-               Bucket *p;
-
+       if (EXPECTED(Z_TYPE_P(array_ptr) == IS_ARRAY)) {
                if (IS_CONST == IS_VAR || IS_CONST == IS_CV) {
                        if (array_ptr == array_ref) {
                                ZVAL_NEW_REF(array_ref, array_ref);
@@ -3219,14 +3192,12 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLE
                        array_ptr = EX_VAR(opline->result.var);
                        ZVAL_COPY_VALUE(array_ptr, array_ref);
                }
-               if (Z_TYPE_P(array_ptr) == IS_ARRAY) {
-                       if (IS_CONST == IS_CONST) {
-                               zval_copy_ctor_func(array_ptr);
-                       } else {
-                               SEPARATE_ARRAY(array_ptr);
-                       }
-                       fe_ht = Z_ARRVAL_P(array_ptr);
+               if (IS_CONST == IS_CONST) {
+                       zval_copy_ctor_func(array_ptr);
+               } else {
+                       SEPARATE_ARRAY(array_ptr);
                }
+               fe_ht = Z_ARRVAL_P(array_ptr);
                while (1) {
                        if (pos >= fe_ht->nNumUsed) {
 
@@ -3234,12 +3205,9 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLE
                                ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
                        }
                        p = fe_ht->arData + pos;
-                       if ((Z_TYPE(p->val) != IS_UNDEF &&
-                            (Z_TYPE(p->val) != IS_INDIRECT ||
-                             Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
-                           (Z_TYPE_P(array_ptr) != IS_OBJECT ||
-                            !p->key ||
-                            zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
+                       if (Z_TYPE(p->val) != IS_UNDEF &&
+                           (Z_TYPE(p->val) != IS_INDIRECT ||
+                            Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) {
                                break;
                        }
                        pos++;
@@ -3249,6 +3217,101 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLE
 
                CHECK_EXCEPTION();
                ZEND_VM_NEXT_OPCODE();
+       } else if (IS_CONST != IS_CONST && EXPECTED(Z_TYPE_P(array_ptr) == IS_OBJECT)) {
+               if (!Z_OBJCE_P(array_ptr)->get_iterator) {
+                       if (IS_CONST == IS_VAR || IS_CONST == IS_CV) {
+                               if (array_ptr == array_ref) {
+                                       ZVAL_NEW_REF(array_ref, array_ref);
+                                       array_ptr = Z_REFVAL_P(array_ref);
+                               }
+                               Z_ADDREF_P(array_ref);
+                               ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref);
+                       } else {
+                               array_ptr = EX_VAR(opline->result.var);
+                               ZVAL_COPY_VALUE(array_ptr, array_ref);
+                       }
+                       fe_ht = Z_OBJPROP_P(array_ptr);
+                       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;
+                               if ((Z_TYPE(p->val) != IS_UNDEF &&
+                                    (Z_TYPE(p->val) != IS_INDIRECT ||
+                                     Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
+                                   (!p->key ||
+                                    zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
+                                       break;
+                               }
+                               pos++;
+                       }
+                       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_class_entry *ce = Z_OBJCE_P(array_ptr);
+                       zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 1);
+                       zend_bool is_empty;
+
+                       if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
+                               if (IS_CONST == IS_VAR) {
+
+                               } else {
+
+                               }
+                               if (!EG(exception)) {
+                                       zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+                               }
+                               zend_throw_exception_internal(NULL);
+                               HANDLE_EXCEPTION();
+                       }
+
+                       iter->index = 0;
+                       if (iter->funcs->rewind) {
+                               iter->funcs->rewind(iter);
+                               if (UNEXPECTED(EG(exception) != NULL)) {
+                                       OBJ_RELEASE(&iter->std);
+                                       if (IS_CONST == IS_VAR) {
+
+                                       } else {
+
+                                       }
+                                       HANDLE_EXCEPTION();
+                               }
+                       }
+
+                       is_empty = iter->funcs->valid(iter) != SUCCESS;
+
+                       if (UNEXPECTED(EG(exception) != NULL)) {
+                               OBJ_RELEASE(&iter->std);
+                               if (IS_CONST == IS_VAR) {
+
+                               } else {
+
+                               }
+                               HANDLE_EXCEPTION();
+                       }
+                       iter->index = -1; /* will be set to 0 before using next handler */
+
+                       ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
+                       Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+
+                       if (IS_CONST == IS_VAR) {
+
+                       } else {
+
+                       }
+                       if (is_empty) {
+                               ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+                       } else {
+                               CHECK_EXCEPTION();
+                               ZEND_VM_NEXT_OPCODE();
+                       }
+               }
        } else {
                zend_error(E_WARNING, "Invalid argument supplied for foreach()");
                ZVAL_UNDEF(EX_VAR(opline->result.var));
@@ -8993,69 +9056,103 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_R_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_A
 {
        USE_OPLINE
        zend_free_op free_op1;
-       zval *array_ptr;
+       zval *array_ptr, *result;
        HashTable *fe_ht;
 
        SAVE_OPLINE();
 
        array_ptr = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1);
-       if (IS_TMP_VAR != IS_CONST &&
-           Z_TYPE_P(array_ptr) == IS_OBJECT && Z_OBJCE_P(array_ptr)->get_iterator) {
-               zend_class_entry *ce = Z_OBJCE_P(array_ptr);
-               zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 0);
-               zend_bool is_empty;
+       if (EXPECTED(Z_TYPE_P(array_ptr) == IS_ARRAY)) {
+               result = EX_VAR(opline->result.var);
+               ZVAL_COPY_VALUE(result, array_ptr);
+               if (IS_TMP_VAR != IS_TMP_VAR && Z_OPT_REFCOUNTED_P(result)) {
+                       Z_ADDREF_P(array_ptr);
+               }
+               Z_FE_POS_P(result) = 0;
 
-               if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
-                       zval_ptr_dtor_nogc(free_op1);
-                       if (!EG(exception)) {
-                               zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+               CHECK_EXCEPTION();
+               ZEND_VM_NEXT_OPCODE();
+       } else if (IS_TMP_VAR != IS_CONST && EXPECTED(Z_TYPE_P(array_ptr) == IS_OBJECT)) {
+               if (!Z_OBJCE_P(array_ptr)->get_iterator) {
+                       HashPosition pos = 0;
+                       Bucket *p;
+
+                       result = EX_VAR(opline->result.var);
+                       ZVAL_COPY_VALUE(result, array_ptr);
+                       if (IS_TMP_VAR != IS_TMP_VAR) {
+                               Z_ADDREF_P(array_ptr);
+                       }
+                       fe_ht = Z_OBJPROP_P(array_ptr);
+                       pos = 0;
+                       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;
+                               if ((Z_TYPE(p->val) != IS_UNDEF &&
+                                    (Z_TYPE(p->val) != IS_INDIRECT ||
+                                     Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
+                                   (!p->key ||
+                                    zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
+                                       break;
+                               }
+                               pos++;
                        }
-                       zend_throw_exception_internal(NULL);
-                       HANDLE_EXCEPTION();
-               }
+                       fe_ht->nInternalPointer = pos;
+                       Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht);
 
-               iter->index = 0;
-               if (iter->funcs->rewind) {
-                       iter->funcs->rewind(iter);
-                       if (UNEXPECTED(EG(exception) != NULL)) {
-                               OBJ_RELEASE(&iter->std);
+                       CHECK_EXCEPTION();
+                       ZEND_VM_NEXT_OPCODE();
+               } else {
+                       zend_class_entry *ce = Z_OBJCE_P(array_ptr);
+                       zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 0);
+                       zend_bool is_empty;
+
+                       if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
                                zval_ptr_dtor_nogc(free_op1);
+                               if (!EG(exception)) {
+                                       zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+                               }
+                               zend_throw_exception_internal(NULL);
                                HANDLE_EXCEPTION();
                        }
-               }
 
-               is_empty = iter->funcs->valid(iter) != SUCCESS;
+                       iter->index = 0;
+                       if (iter->funcs->rewind) {
+                               iter->funcs->rewind(iter);
+                               if (UNEXPECTED(EG(exception) != NULL)) {
+                                       OBJ_RELEASE(&iter->std);
+                                       zval_ptr_dtor_nogc(free_op1);
+                                       HANDLE_EXCEPTION();
+                               }
+                       }
 
-               if (UNEXPECTED(EG(exception) != NULL)) {
-                       OBJ_RELEASE(&iter->std);
-                       zval_ptr_dtor_nogc(free_op1);
-                       HANDLE_EXCEPTION();
-               }
-               iter->index = -1; /* will be set to 0 before using next handler */
+                       is_empty = iter->funcs->valid(iter) != SUCCESS;
 
-               ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
+                       if (UNEXPECTED(EG(exception) != NULL)) {
+                               OBJ_RELEASE(&iter->std);
+                               zval_ptr_dtor_nogc(free_op1);
+                               HANDLE_EXCEPTION();
+                       }
+                       iter->index = -1; /* will be set to 0 before using next handler */
 
-               zval_ptr_dtor_nogc(free_op1);
-               if (is_empty) {
-                       ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
-               } else {
-                       CHECK_EXCEPTION();
-                       ZEND_VM_NEXT_OPCODE();
-               }
-       } else if ((fe_ht = HASH_OF(array_ptr)) != NULL) {
-               zval *result = EX_VAR(opline->result.var);
+                       ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
+                       Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
 
-               ZVAL_COPY_VALUE(result, array_ptr);
-               if (IS_TMP_VAR != IS_TMP_VAR && Z_OPT_REFCOUNTED_P(result)) {
-                       Z_ADDREF_P(array_ptr);
+                       zval_ptr_dtor_nogc(free_op1);
+                       if (is_empty) {
+                               ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+                       } else {
+                               CHECK_EXCEPTION();
+                               ZEND_VM_NEXT_OPCODE();
+                       }
                }
-               Z_FE_POS_P(result) = 0;
-
-               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;
                zval_ptr_dtor_nogc(free_op1);
                ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
        }
@@ -9067,6 +9164,8 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_
        zend_free_op free_op1;
        zval *array_ptr, *array_ref;
        HashTable *fe_ht;
+       HashPosition pos = 0;
+       Bucket *p;
 
        SAVE_OPLINE();
 
@@ -9079,70 +9178,7 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_
                array_ref = array_ptr = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1);
        }
 
-       if (IS_TMP_VAR != IS_CONST &&
-           Z_TYPE_P(array_ptr) == IS_OBJECT && Z_OBJCE_P(array_ptr)->get_iterator) {
-               zend_class_entry *ce = Z_OBJCE_P(array_ptr);
-               zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 1);
-               zend_bool is_empty;
-
-               if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
-                       if (IS_TMP_VAR == IS_VAR) {
-
-                       } else {
-                               zval_ptr_dtor_nogc(free_op1);
-                       }
-                       if (!EG(exception)) {
-                               zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
-                       }
-                       zend_throw_exception_internal(NULL);
-                       HANDLE_EXCEPTION();
-               }
-
-               iter->index = 0;
-               if (iter->funcs->rewind) {
-                       iter->funcs->rewind(iter);
-                       if (UNEXPECTED(EG(exception) != NULL)) {
-                               OBJ_RELEASE(&iter->std);
-                               if (IS_TMP_VAR == IS_VAR) {
-
-                               } else {
-                                       zval_ptr_dtor_nogc(free_op1);
-                               }
-                               HANDLE_EXCEPTION();
-                       }
-               }
-
-               is_empty = iter->funcs->valid(iter) != SUCCESS;
-
-               if (UNEXPECTED(EG(exception) != NULL)) {
-                       OBJ_RELEASE(&iter->std);
-                       if (IS_TMP_VAR == IS_VAR) {
-
-                       } else {
-                               zval_ptr_dtor_nogc(free_op1);
-                       }
-                       HANDLE_EXCEPTION();
-               }
-               iter->index = -1; /* will be set to 0 before using next handler */
-
-               ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
-               Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
-
-               if (IS_TMP_VAR == IS_VAR) {
-
-               } else {
-                       zval_ptr_dtor_nogc(free_op1);
-               }
-               if (is_empty) {
-                       ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
-               } else {
-                       CHECK_EXCEPTION();
-                       ZEND_VM_NEXT_OPCODE();
-               }
-       } else if ((fe_ht = HASH_OF(array_ptr)) != NULL) {
-               HashPosition pos = 0;
-               Bucket *p;
-
+       if (EXPECTED(Z_TYPE_P(array_ptr) == IS_ARRAY)) {
                if (IS_TMP_VAR == IS_VAR || IS_TMP_VAR == IS_CV) {
                        if (array_ptr == array_ref) {
                                ZVAL_NEW_REF(array_ref, array_ref);
@@ -9154,14 +9190,12 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_
                        array_ptr = EX_VAR(opline->result.var);
                        ZVAL_COPY_VALUE(array_ptr, array_ref);
                }
-               if (Z_TYPE_P(array_ptr) == IS_ARRAY) {
-                       if (IS_TMP_VAR == IS_CONST) {
-                               zval_copy_ctor_func(array_ptr);
-                       } else {
-                               SEPARATE_ARRAY(array_ptr);
-                       }
-                       fe_ht = Z_ARRVAL_P(array_ptr);
+               if (IS_TMP_VAR == IS_CONST) {
+                       zval_copy_ctor_func(array_ptr);
+               } else {
+                       SEPARATE_ARRAY(array_ptr);
                }
+               fe_ht = Z_ARRVAL_P(array_ptr);
                while (1) {
                        if (pos >= fe_ht->nNumUsed) {
 
@@ -9169,12 +9203,9 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_
                                ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
                        }
                        p = fe_ht->arData + pos;
-                       if ((Z_TYPE(p->val) != IS_UNDEF &&
-                            (Z_TYPE(p->val) != IS_INDIRECT ||
-                             Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
-                           (Z_TYPE_P(array_ptr) != IS_OBJECT ||
-                            !p->key ||
-                            zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
+                       if (Z_TYPE(p->val) != IS_UNDEF &&
+                           (Z_TYPE(p->val) != IS_INDIRECT ||
+                            Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) {
                                break;
                        }
                        pos++;
@@ -9184,6 +9215,101 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_
 
                CHECK_EXCEPTION();
                ZEND_VM_NEXT_OPCODE();
+       } else if (IS_TMP_VAR != IS_CONST && EXPECTED(Z_TYPE_P(array_ptr) == IS_OBJECT)) {
+               if (!Z_OBJCE_P(array_ptr)->get_iterator) {
+                       if (IS_TMP_VAR == IS_VAR || IS_TMP_VAR == IS_CV) {
+                               if (array_ptr == array_ref) {
+                                       ZVAL_NEW_REF(array_ref, array_ref);
+                                       array_ptr = Z_REFVAL_P(array_ref);
+                               }
+                               Z_ADDREF_P(array_ref);
+                               ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref);
+                       } else {
+                               array_ptr = EX_VAR(opline->result.var);
+                               ZVAL_COPY_VALUE(array_ptr, array_ref);
+                       }
+                       fe_ht = Z_OBJPROP_P(array_ptr);
+                       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;
+                               if ((Z_TYPE(p->val) != IS_UNDEF &&
+                                    (Z_TYPE(p->val) != IS_INDIRECT ||
+                                     Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
+                                   (!p->key ||
+                                    zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
+                                       break;
+                               }
+                               pos++;
+                       }
+                       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_class_entry *ce = Z_OBJCE_P(array_ptr);
+                       zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 1);
+                       zend_bool is_empty;
+
+                       if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
+                               if (IS_TMP_VAR == IS_VAR) {
+
+                               } else {
+                                       zval_ptr_dtor_nogc(free_op1);
+                               }
+                               if (!EG(exception)) {
+                                       zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+                               }
+                               zend_throw_exception_internal(NULL);
+                               HANDLE_EXCEPTION();
+                       }
+
+                       iter->index = 0;
+                       if (iter->funcs->rewind) {
+                               iter->funcs->rewind(iter);
+                               if (UNEXPECTED(EG(exception) != NULL)) {
+                                       OBJ_RELEASE(&iter->std);
+                                       if (IS_TMP_VAR == IS_VAR) {
+
+                                       } else {
+                                               zval_ptr_dtor_nogc(free_op1);
+                                       }
+                                       HANDLE_EXCEPTION();
+                               }
+                       }
+
+                       is_empty = iter->funcs->valid(iter) != SUCCESS;
+
+                       if (UNEXPECTED(EG(exception) != NULL)) {
+                               OBJ_RELEASE(&iter->std);
+                               if (IS_TMP_VAR == IS_VAR) {
+
+                               } else {
+                                       zval_ptr_dtor_nogc(free_op1);
+                               }
+                               HANDLE_EXCEPTION();
+                       }
+                       iter->index = -1; /* will be set to 0 before using next handler */
+
+                       ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
+                       Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+
+                       if (IS_TMP_VAR == IS_VAR) {
+
+                       } else {
+                               zval_ptr_dtor_nogc(free_op1);
+                       }
+                       if (is_empty) {
+                               ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+                       } else {
+                               CHECK_EXCEPTION();
+                               ZEND_VM_NEXT_OPCODE();
+                       }
+               }
        } else {
                zend_error(E_WARNING, "Invalid argument supplied for foreach()");
                ZVAL_UNDEF(EX_VAR(opline->result.var));
@@ -11829,70 +11955,105 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_R_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_A
 {
        USE_OPLINE
        zend_free_op free_op1;
-       zval *array_ptr;
+       zval *array_ptr, *result;
        HashTable *fe_ht;
 
        SAVE_OPLINE();
 
        array_ptr = _get_zval_ptr_var_deref(opline->op1.var, execute_data, &free_op1);
-       if (IS_VAR != IS_CONST &&
-           Z_TYPE_P(array_ptr) == IS_OBJECT && Z_OBJCE_P(array_ptr)->get_iterator) {
-               zend_class_entry *ce = Z_OBJCE_P(array_ptr);
-               zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 0);
-               zend_bool is_empty;
+       if (EXPECTED(Z_TYPE_P(array_ptr) == IS_ARRAY)) {
+               result = EX_VAR(opline->result.var);
+               ZVAL_COPY_VALUE(result, array_ptr);
+               if (IS_VAR != IS_TMP_VAR && Z_OPT_REFCOUNTED_P(result)) {
+                       Z_ADDREF_P(array_ptr);
+               }
+               Z_FE_POS_P(result) = 0;
+
+               zval_ptr_dtor_nogc(free_op1);
+               CHECK_EXCEPTION();
+               ZEND_VM_NEXT_OPCODE();
+       } else if (IS_VAR != IS_CONST && EXPECTED(Z_TYPE_P(array_ptr) == IS_OBJECT)) {
+               if (!Z_OBJCE_P(array_ptr)->get_iterator) {
+                       HashPosition pos = 0;
+                       Bucket *p;
+
+                       result = EX_VAR(opline->result.var);
+                       ZVAL_COPY_VALUE(result, array_ptr);
+                       if (IS_VAR != IS_TMP_VAR) {
+                               Z_ADDREF_P(array_ptr);
+                       }
+                       fe_ht = Z_OBJPROP_P(array_ptr);
+                       pos = 0;
+                       while (1) {
+                               if (pos >= fe_ht->nNumUsed) {
+                                       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;
+                               if ((Z_TYPE(p->val) != IS_UNDEF &&
+                                    (Z_TYPE(p->val) != IS_INDIRECT ||
+                                     Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
+                                   (!p->key ||
+                                    zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
+                                       break;
+                               }
+                               pos++;
+                       }
+                       fe_ht->nInternalPointer = pos;
+                       Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht);
 
-               if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
                        zval_ptr_dtor_nogc(free_op1);
-                       if (!EG(exception)) {
-                               zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+                       CHECK_EXCEPTION();
+                       ZEND_VM_NEXT_OPCODE();
+               } else {
+                       zend_class_entry *ce = Z_OBJCE_P(array_ptr);
+                       zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 0);
+                       zend_bool is_empty;
+
+                       if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
+                               zval_ptr_dtor_nogc(free_op1);
+                               if (!EG(exception)) {
+                                       zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+                               }
+                               zend_throw_exception_internal(NULL);
+                               HANDLE_EXCEPTION();
                        }
-                       zend_throw_exception_internal(NULL);
-                       HANDLE_EXCEPTION();
-               }
 
-               iter->index = 0;
-               if (iter->funcs->rewind) {
-                       iter->funcs->rewind(iter);
+                       iter->index = 0;
+                       if (iter->funcs->rewind) {
+                               iter->funcs->rewind(iter);
+                               if (UNEXPECTED(EG(exception) != NULL)) {
+                                       OBJ_RELEASE(&iter->std);
+                                       zval_ptr_dtor_nogc(free_op1);
+                                       HANDLE_EXCEPTION();
+                               }
+                       }
+
+                       is_empty = iter->funcs->valid(iter) != SUCCESS;
+
                        if (UNEXPECTED(EG(exception) != NULL)) {
                                OBJ_RELEASE(&iter->std);
                                zval_ptr_dtor_nogc(free_op1);
                                HANDLE_EXCEPTION();
                        }
-               }
+                       iter->index = -1; /* will be set to 0 before using next handler */
 
-               is_empty = iter->funcs->valid(iter) != SUCCESS;
+                       ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
+                       Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
 
-               if (UNEXPECTED(EG(exception) != NULL)) {
-                       OBJ_RELEASE(&iter->std);
                        zval_ptr_dtor_nogc(free_op1);
-                       HANDLE_EXCEPTION();
-               }
-               iter->index = -1; /* will be set to 0 before using next handler */
-
-               ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
-
-               zval_ptr_dtor_nogc(free_op1);
-               if (is_empty) {
-                       ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
-               } else {
-                       CHECK_EXCEPTION();
-                       ZEND_VM_NEXT_OPCODE();
-               }
-       } else if ((fe_ht = HASH_OF(array_ptr)) != NULL) {
-               zval *result = EX_VAR(opline->result.var);
-
-               ZVAL_COPY_VALUE(result, array_ptr);
-               if (IS_VAR != IS_TMP_VAR && Z_OPT_REFCOUNTED_P(result)) {
-                       Z_ADDREF_P(array_ptr);
+                       if (is_empty) {
+                               ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+                       } else {
+                               CHECK_EXCEPTION();
+                               ZEND_VM_NEXT_OPCODE();
+                       }
                }
-               Z_FE_POS_P(result) = 0;
-
-               zval_ptr_dtor_nogc(free_op1);
-               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;
                zval_ptr_dtor_nogc(free_op1);
                ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
        }
@@ -11904,6 +12065,8 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_
        zend_free_op free_op1;
        zval *array_ptr, *array_ref;
        HashTable *fe_ht;
+       HashPosition pos = 0;
+       Bucket *p;
 
        SAVE_OPLINE();
 
@@ -11916,28 +12079,114 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_
                array_ref = array_ptr = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1);
        }
 
-       if (IS_VAR != IS_CONST &&
-           Z_TYPE_P(array_ptr) == IS_OBJECT && Z_OBJCE_P(array_ptr)->get_iterator) {
-               zend_class_entry *ce = Z_OBJCE_P(array_ptr);
-               zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 1);
-               zend_bool is_empty;
-
-               if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
-                       if (IS_VAR == IS_VAR) {
+       if (EXPECTED(Z_TYPE_P(array_ptr) == IS_ARRAY)) {
+               if (IS_VAR == IS_VAR || IS_VAR == IS_CV) {
+                       if (array_ptr == array_ref) {
+                               ZVAL_NEW_REF(array_ref, array_ref);
+                               array_ptr = Z_REFVAL_P(array_ref);
+                       }
+                       Z_ADDREF_P(array_ref);
+                       ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref);
+               } else {
+                       array_ptr = EX_VAR(opline->result.var);
+                       ZVAL_COPY_VALUE(array_ptr, array_ref);
+               }
+               if (IS_VAR == IS_CONST) {
+                       zval_copy_ctor_func(array_ptr);
+               } else {
+                       SEPARATE_ARRAY(array_ptr);
+               }
+               fe_ht = Z_ARRVAL_P(array_ptr);
+               while (1) {
+                       if (pos >= fe_ht->nNumUsed) {
                                if (free_op1) {zval_ptr_dtor_nogc(free_op1);};
-                       } else {
-                               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));
                        }
-                       if (!EG(exception)) {
-                               zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+                       p = fe_ht->arData + pos;
+                       if (Z_TYPE(p->val) != IS_UNDEF &&
+                           (Z_TYPE(p->val) != IS_INDIRECT ||
+                            Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) {
+                               break;
                        }
-                       zend_throw_exception_internal(NULL);
-                       HANDLE_EXCEPTION();
+                       pos++;
                }
+               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();
+               ZEND_VM_NEXT_OPCODE();
+       } else if (IS_VAR != IS_CONST && EXPECTED(Z_TYPE_P(array_ptr) == IS_OBJECT)) {
+               if (!Z_OBJCE_P(array_ptr)->get_iterator) {
+                       if (IS_VAR == IS_VAR || IS_VAR == IS_CV) {
+                               if (array_ptr == array_ref) {
+                                       ZVAL_NEW_REF(array_ref, array_ref);
+                                       array_ptr = Z_REFVAL_P(array_ref);
+                               }
+                               Z_ADDREF_P(array_ref);
+                               ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref);
+                       } else {
+                               array_ptr = EX_VAR(opline->result.var);
+                               ZVAL_COPY_VALUE(array_ptr, array_ref);
+                       }
+                       fe_ht = Z_OBJPROP_P(array_ptr);
+                       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;
+                               if ((Z_TYPE(p->val) != IS_UNDEF &&
+                                    (Z_TYPE(p->val) != IS_INDIRECT ||
+                                     Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
+                                   (!p->key ||
+                                    zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
+                                       break;
+                               }
+                               pos++;
+                       }
+                       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();
+                       ZEND_VM_NEXT_OPCODE();
+               } else {
+                       zend_class_entry *ce = Z_OBJCE_P(array_ptr);
+                       zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 1);
+                       zend_bool is_empty;
+
+                       if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
+                               if (IS_VAR == IS_VAR) {
+                                       if (free_op1) {zval_ptr_dtor_nogc(free_op1);};
+                               } else {
+                                       zval_ptr_dtor_nogc(free_op1);
+                               }
+                               if (!EG(exception)) {
+                                       zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+                               }
+                               zend_throw_exception_internal(NULL);
+                               HANDLE_EXCEPTION();
+                       }
+
+                       iter->index = 0;
+                       if (iter->funcs->rewind) {
+                               iter->funcs->rewind(iter);
+                               if (UNEXPECTED(EG(exception) != NULL)) {
+                                       OBJ_RELEASE(&iter->std);
+                                       if (IS_VAR == IS_VAR) {
+                                               if (free_op1) {zval_ptr_dtor_nogc(free_op1);};
+                                       } else {
+                                               zval_ptr_dtor_nogc(free_op1);
+                                       }
+                                       HANDLE_EXCEPTION();
+                               }
+                       }
+
+                       is_empty = iter->funcs->valid(iter) != SUCCESS;
 
-               iter->index = 0;
-               if (iter->funcs->rewind) {
-                       iter->funcs->rewind(iter);
                        if (UNEXPECTED(EG(exception) != NULL)) {
                                OBJ_RELEASE(&iter->std);
                                if (IS_VAR == IS_VAR) {
@@ -11947,81 +12196,23 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_
                                }
                                HANDLE_EXCEPTION();
                        }
-               }
+                       iter->index = -1; /* will be set to 0 before using next handler */
 
-               is_empty = iter->funcs->valid(iter) != SUCCESS;
+                       ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
+                       Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
 
-               if (UNEXPECTED(EG(exception) != NULL)) {
-                       OBJ_RELEASE(&iter->std);
                        if (IS_VAR == IS_VAR) {
                                if (free_op1) {zval_ptr_dtor_nogc(free_op1);};
                        } else {
                                zval_ptr_dtor_nogc(free_op1);
                        }
-                       HANDLE_EXCEPTION();
-               }
-               iter->index = -1; /* will be set to 0 before using next handler */
-
-               ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
-               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 {
-                       zval_ptr_dtor_nogc(free_op1);
-               }
-               if (is_empty) {
-                       ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
-               } else {
-                       CHECK_EXCEPTION();
-                       ZEND_VM_NEXT_OPCODE();
-               }
-       } else if ((fe_ht = HASH_OF(array_ptr)) != NULL) {
-               HashPosition pos = 0;
-               Bucket *p;
-
-               if (IS_VAR == IS_VAR || IS_VAR == IS_CV) {
-                       if (array_ptr == array_ref) {
-                               ZVAL_NEW_REF(array_ref, array_ref);
-                               array_ptr = Z_REFVAL_P(array_ref);
-                       }
-                       Z_ADDREF_P(array_ref);
-                       ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref);
-               } else {
-                       array_ptr = EX_VAR(opline->result.var);
-                       ZVAL_COPY_VALUE(array_ptr, array_ref);
-               }
-               if (Z_TYPE_P(array_ptr) == IS_ARRAY) {
-                       if (IS_VAR == IS_CONST) {
-                               zval_copy_ctor_func(array_ptr);
-                       } else {
-                               SEPARATE_ARRAY(array_ptr);
-                       }
-                       fe_ht = Z_ARRVAL_P(array_ptr);
-               }
-               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;
+                       if (is_empty) {
                                ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+                       } else {
+                               CHECK_EXCEPTION();
+                               ZEND_VM_NEXT_OPCODE();
                        }
-                       p = fe_ht->arData + pos;
-                       if ((Z_TYPE(p->val) != IS_UNDEF &&
-                            (Z_TYPE(p->val) != IS_INDIRECT ||
-                             Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
-                           (Z_TYPE_P(array_ptr) != IS_OBJECT ||
-                            !p->key ||
-                            zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
-                               break;
-                       }
-                       pos++;
                }
-               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();
-               ZEND_VM_NEXT_OPCODE();
        } else {
                zend_error(E_WARNING, "Invalid argument supplied for foreach()");
                ZVAL_UNDEF(EX_VAR(opline->result.var));
@@ -12088,7 +12279,7 @@ static int ZEND_FASTCALL  ZEND_FE_FETCH_R_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_A
                        zend_object *zobj = Z_OBJ_P(array);
 
                        fe_ht = Z_OBJPROP_P(array);
-                       pos = Z_FE_POS_P(EX_VAR(opline->op1.var));
+                       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 */
@@ -12127,7 +12318,24 @@ static int ZEND_FASTCALL  ZEND_FE_FETCH_R_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_A
                                }
                        }
                        ZVAL_COPY(EX_VAR(opline->result.var), value);
-                       Z_FE_POS_P(EX_VAR(opline->op1.var)) = pos + 1;
+                       while (1) {
+                               pos++;
+                               if (pos >= fe_ht->nNumUsed) {
+                                       pos = INVALID_IDX;
+                                       break;
+                               }
+                               p = fe_ht->arData + pos;
+                               if ((Z_TYPE(p->val) != IS_UNDEF &&
+                                    (Z_TYPE(p->val) != IS_INDIRECT ||
+                                     Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
+                                   (Z_TYPE_P(array) != IS_OBJECT ||
+                                    !p->key ||
+                                    zend_check_property_access(Z_OBJ_P(array), p->key) == SUCCESS)) {
+                                       break;
+                               }
+                       }
+                       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 {
@@ -24217,68 +24425,102 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_R_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_AR
 {
        USE_OPLINE
 
-       zval *array_ptr;
+       zval *array_ptr, *result;
        HashTable *fe_ht;
 
        SAVE_OPLINE();
 
        array_ptr = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op1.var);
-       if (IS_CV != IS_CONST &&
-           Z_TYPE_P(array_ptr) == IS_OBJECT && Z_OBJCE_P(array_ptr)->get_iterator) {
-               zend_class_entry *ce = Z_OBJCE_P(array_ptr);
-               zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 0);
-               zend_bool is_empty;
+       if (EXPECTED(Z_TYPE_P(array_ptr) == IS_ARRAY)) {
+               result = EX_VAR(opline->result.var);
+               ZVAL_COPY_VALUE(result, array_ptr);
+               if (IS_CV != IS_TMP_VAR && Z_OPT_REFCOUNTED_P(result)) {
+                       Z_ADDREF_P(array_ptr);
+               }
+               Z_FE_POS_P(result) = 0;
 
-               if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
+               CHECK_EXCEPTION();
+               ZEND_VM_NEXT_OPCODE();
+       } else if (IS_CV != IS_CONST && EXPECTED(Z_TYPE_P(array_ptr) == IS_OBJECT)) {
+               if (!Z_OBJCE_P(array_ptr)->get_iterator) {
+                       HashPosition pos = 0;
+                       Bucket *p;
+
+                       result = EX_VAR(opline->result.var);
+                       ZVAL_COPY_VALUE(result, array_ptr);
+                       if (IS_CV != IS_TMP_VAR) {
+                               Z_ADDREF_P(array_ptr);
+                       }
+                       fe_ht = Z_OBJPROP_P(array_ptr);
+                       pos = 0;
+                       while (1) {
+                               if (pos >= fe_ht->nNumUsed) {
 
-                       if (!EG(exception)) {
-                               zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+                                       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;
+                               if ((Z_TYPE(p->val) != IS_UNDEF &&
+                                    (Z_TYPE(p->val) != IS_INDIRECT ||
+                                     Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
+                                   (!p->key ||
+                                    zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
+                                       break;
+                               }
+                               pos++;
                        }
-                       zend_throw_exception_internal(NULL);
-                       HANDLE_EXCEPTION();
-               }
+                       fe_ht->nInternalPointer = pos;
+                       Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht);
 
-               iter->index = 0;
-               if (iter->funcs->rewind) {
-                       iter->funcs->rewind(iter);
-                       if (UNEXPECTED(EG(exception) != NULL)) {
-                               OBJ_RELEASE(&iter->std);
+                       CHECK_EXCEPTION();
+                       ZEND_VM_NEXT_OPCODE();
+               } else {
+                       zend_class_entry *ce = Z_OBJCE_P(array_ptr);
+                       zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 0);
+                       zend_bool is_empty;
 
+                       if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
+
+                               if (!EG(exception)) {
+                                       zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+                               }
+                               zend_throw_exception_internal(NULL);
                                HANDLE_EXCEPTION();
                        }
-               }
 
-               is_empty = iter->funcs->valid(iter) != SUCCESS;
+                       iter->index = 0;
+                       if (iter->funcs->rewind) {
+                               iter->funcs->rewind(iter);
+                               if (UNEXPECTED(EG(exception) != NULL)) {
+                                       OBJ_RELEASE(&iter->std);
 
-               if (UNEXPECTED(EG(exception) != NULL)) {
-                       OBJ_RELEASE(&iter->std);
+                                       HANDLE_EXCEPTION();
+                               }
+                       }
 
-                       HANDLE_EXCEPTION();
-               }
-               iter->index = -1; /* will be set to 0 before using next handler */
+                       is_empty = iter->funcs->valid(iter) != SUCCESS;
 
-               ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
+                       if (UNEXPECTED(EG(exception) != NULL)) {
+                               OBJ_RELEASE(&iter->std);
 
-               if (is_empty) {
-                       ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
-               } else {
-                       CHECK_EXCEPTION();
-                       ZEND_VM_NEXT_OPCODE();
-               }
-       } else if ((fe_ht = HASH_OF(array_ptr)) != NULL) {
-               zval *result = EX_VAR(opline->result.var);
+                               HANDLE_EXCEPTION();
+                       }
+                       iter->index = -1; /* will be set to 0 before using next handler */
 
-               ZVAL_COPY_VALUE(result, array_ptr);
-               if (IS_CV != IS_TMP_VAR && Z_OPT_REFCOUNTED_P(result)) {
-                       Z_ADDREF_P(array_ptr);
-               }
-               Z_FE_POS_P(result) = 0;
+                       ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
+                       Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
 
-               CHECK_EXCEPTION();
-               ZEND_VM_NEXT_OPCODE();
+                       if (is_empty) {
+                               ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+                       } else {
+                               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;
 
                ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
        }
@@ -24290,6 +24532,8 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_A
 
        zval *array_ptr, *array_ref;
        HashTable *fe_ht;
+       HashPosition pos = 0;
+       Bucket *p;
 
        SAVE_OPLINE();
 
@@ -24302,70 +24546,7 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_A
                array_ref = array_ptr = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var);
        }
 
-       if (IS_CV != IS_CONST &&
-           Z_TYPE_P(array_ptr) == IS_OBJECT && Z_OBJCE_P(array_ptr)->get_iterator) {
-               zend_class_entry *ce = Z_OBJCE_P(array_ptr);
-               zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 1);
-               zend_bool is_empty;
-
-               if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
-                       if (IS_CV == IS_VAR) {
-
-                       } else {
-
-                       }
-                       if (!EG(exception)) {
-                               zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
-                       }
-                       zend_throw_exception_internal(NULL);
-                       HANDLE_EXCEPTION();
-               }
-
-               iter->index = 0;
-               if (iter->funcs->rewind) {
-                       iter->funcs->rewind(iter);
-                       if (UNEXPECTED(EG(exception) != NULL)) {
-                               OBJ_RELEASE(&iter->std);
-                               if (IS_CV == IS_VAR) {
-
-                               } else {
-
-                               }
-                               HANDLE_EXCEPTION();
-                       }
-               }
-
-               is_empty = iter->funcs->valid(iter) != SUCCESS;
-
-               if (UNEXPECTED(EG(exception) != NULL)) {
-                       OBJ_RELEASE(&iter->std);
-                       if (IS_CV == IS_VAR) {
-
-                       } else {
-
-                       }
-                       HANDLE_EXCEPTION();
-               }
-               iter->index = -1; /* will be set to 0 before using next handler */
-
-               ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
-               Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
-
-               if (IS_CV == IS_VAR) {
-
-               } else {
-
-               }
-               if (is_empty) {
-                       ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
-               } else {
-                       CHECK_EXCEPTION();
-                       ZEND_VM_NEXT_OPCODE();
-               }
-       } else if ((fe_ht = HASH_OF(array_ptr)) != NULL) {
-               HashPosition pos = 0;
-               Bucket *p;
-
+       if (EXPECTED(Z_TYPE_P(array_ptr) == IS_ARRAY)) {
                if (IS_CV == IS_VAR || IS_CV == IS_CV) {
                        if (array_ptr == array_ref) {
                                ZVAL_NEW_REF(array_ref, array_ref);
@@ -24377,14 +24558,12 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_A
                        array_ptr = EX_VAR(opline->result.var);
                        ZVAL_COPY_VALUE(array_ptr, array_ref);
                }
-               if (Z_TYPE_P(array_ptr) == IS_ARRAY) {
-                       if (IS_CV == IS_CONST) {
-                               zval_copy_ctor_func(array_ptr);
-                       } else {
-                               SEPARATE_ARRAY(array_ptr);
-                       }
-                       fe_ht = Z_ARRVAL_P(array_ptr);
+               if (IS_CV == IS_CONST) {
+                       zval_copy_ctor_func(array_ptr);
+               } else {
+                       SEPARATE_ARRAY(array_ptr);
                }
+               fe_ht = Z_ARRVAL_P(array_ptr);
                while (1) {
                        if (pos >= fe_ht->nNumUsed) {
 
@@ -24392,12 +24571,9 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_A
                                ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
                        }
                        p = fe_ht->arData + pos;
-                       if ((Z_TYPE(p->val) != IS_UNDEF &&
-                            (Z_TYPE(p->val) != IS_INDIRECT ||
-                             Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
-                           (Z_TYPE_P(array_ptr) != IS_OBJECT ||
-                            !p->key ||
-                            zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
+                       if (Z_TYPE(p->val) != IS_UNDEF &&
+                           (Z_TYPE(p->val) != IS_INDIRECT ||
+                            Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) {
                                break;
                        }
                        pos++;
@@ -24407,6 +24583,101 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_A
 
                CHECK_EXCEPTION();
                ZEND_VM_NEXT_OPCODE();
+       } else if (IS_CV != IS_CONST && EXPECTED(Z_TYPE_P(array_ptr) == IS_OBJECT)) {
+               if (!Z_OBJCE_P(array_ptr)->get_iterator) {
+                       if (IS_CV == IS_VAR || IS_CV == IS_CV) {
+                               if (array_ptr == array_ref) {
+                                       ZVAL_NEW_REF(array_ref, array_ref);
+                                       array_ptr = Z_REFVAL_P(array_ref);
+                               }
+                               Z_ADDREF_P(array_ref);
+                               ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref);
+                       } else {
+                               array_ptr = EX_VAR(opline->result.var);
+                               ZVAL_COPY_VALUE(array_ptr, array_ref);
+                       }
+                       fe_ht = Z_OBJPROP_P(array_ptr);
+                       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;
+                               if ((Z_TYPE(p->val) != IS_UNDEF &&
+                                    (Z_TYPE(p->val) != IS_INDIRECT ||
+                                     Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
+                                   (!p->key ||
+                                    zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
+                                       break;
+                               }
+                               pos++;
+                       }
+                       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_class_entry *ce = Z_OBJCE_P(array_ptr);
+                       zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 1);
+                       zend_bool is_empty;
+
+                       if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
+                               if (IS_CV == IS_VAR) {
+
+                               } else {
+
+                               }
+                               if (!EG(exception)) {
+                                       zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+                               }
+                               zend_throw_exception_internal(NULL);
+                               HANDLE_EXCEPTION();
+                       }
+
+                       iter->index = 0;
+                       if (iter->funcs->rewind) {
+                               iter->funcs->rewind(iter);
+                               if (UNEXPECTED(EG(exception) != NULL)) {
+                                       OBJ_RELEASE(&iter->std);
+                                       if (IS_CV == IS_VAR) {
+
+                                       } else {
+
+                                       }
+                                       HANDLE_EXCEPTION();
+                               }
+                       }
+
+                       is_empty = iter->funcs->valid(iter) != SUCCESS;
+
+                       if (UNEXPECTED(EG(exception) != NULL)) {
+                               OBJ_RELEASE(&iter->std);
+                               if (IS_CV == IS_VAR) {
+
+                               } else {
+
+                               }
+                               HANDLE_EXCEPTION();
+                       }
+                       iter->index = -1; /* will be set to 0 before using next handler */
+
+                       ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
+                       Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+
+                       if (IS_CV == IS_VAR) {
+
+                       } else {
+
+                       }
+                       if (is_empty) {
+                               ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+                       } else {
+                               CHECK_EXCEPTION();
+                               ZEND_VM_NEXT_OPCODE();
+                       }
+               }
        } else {
                zend_error(E_WARNING, "Invalid argument supplied for foreach()");
                ZVAL_UNDEF(EX_VAR(opline->result.var));
@@ -33147,7 +33418,7 @@ static int ZEND_FASTCALL  ZEND_FE_FREE_SPEC_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_A
 
        SAVE_OPLINE();
        var = EX_VAR(opline->op1.var);
-       if (Z_FE_ITER_P(var) != (uint32_t)-1) {
+       if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
                zend_hash_iterator_del(Z_FE_ITER_P(var));
        }
        zval_ptr_dtor_nogc(var);