summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2015-01-30 09:49:35 +0300
committerDmitry Stogov <dmitry@zend.com>2015-01-30 09:49:35 +0300
commit5aa9712b0a30303aadfe3bdd8ae1f072ca3e6ba1 (patch)
treece255b4325e5fe232fb9e4a4dfb5e2ceec9f1b74
parent4c5b385ff53ae9f0b52572e98c4db801f56603b0 (diff)
downloadphp-git-5aa9712b0a30303aadfe3bdd8ae1f072ca3e6ba1.tar.gz
Implement consistent behavior for foreach by value over plain object
-rw-r--r--Zend/tests/foreach_010.phpt40
-rw-r--r--Zend/zend_compile.c2
-rw-r--r--Zend/zend_execute.c2
-rw-r--r--Zend/zend_generators.c2
-rw-r--r--Zend/zend_vm_def.h336
-rw-r--r--Zend/zend_vm_execute.h1229
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);