diff options
author | Dmitry Stogov <dmitry@zend.com> | 2015-01-30 09:49:35 +0300 |
---|---|---|
committer | Dmitry Stogov <dmitry@zend.com> | 2015-01-30 09:49:35 +0300 |
commit | 5aa9712b0a30303aadfe3bdd8ae1f072ca3e6ba1 (patch) | |
tree | ce255b4325e5fe232fb9e4a4dfb5e2ceec9f1b74 | |
parent | 4c5b385ff53ae9f0b52572e98c4db801f56603b0 (diff) | |
download | php-git-5aa9712b0a30303aadfe3bdd8ae1f072ca3e6ba1.tar.gz |
Implement consistent behavior for foreach by value over plain object
-rw-r--r-- | Zend/tests/foreach_010.phpt | 40 | ||||
-rw-r--r-- | Zend/zend_compile.c | 2 | ||||
-rw-r--r-- | Zend/zend_execute.c | 2 | ||||
-rw-r--r-- | Zend/zend_generators.c | 2 | ||||
-rw-r--r-- | Zend/zend_vm_def.h | 336 | ||||
-rw-r--r-- | Zend/zend_vm_execute.h | 1229 |
6 files changed, 1002 insertions, 609 deletions
diff --git a/Zend/tests/foreach_010.phpt b/Zend/tests/foreach_010.phpt new file mode 100644 index 0000000000..6ba7e7e9fd --- /dev/null +++ b/Zend/tests/foreach_010.phpt @@ -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 diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 080b31562a..79293971e8 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -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)); diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index d59aef1d1b..1a81c298a8 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -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); diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index 1f25d07ea9..971d4e7bc8 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -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); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 245bc0b68a..064c756c6e 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -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); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 4244f5f750..8ae97d2bf8 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -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,70 +12079,7 @@ 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 (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; - - 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 (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); @@ -11991,14 +12091,12 @@ static int ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_VAR_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_VAR == IS_CONST) { - zval_copy_ctor_func(array_ptr); - } else { - SEPARATE_ARRAY(array_ptr); - } - fe_ht = Z_ARRVAL_P(array_ptr); + 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);}; @@ -12006,12 +12104,9 @@ static int ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_VAR_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++; @@ -12022,6 +12117,102 @@ static int ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ 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; + + 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 { 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); |