summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2015-01-28 07:43:28 +0300
committerDmitry Stogov <dmitry@zend.com>2015-01-28 07:43:28 +0300
commit4638f7b91407c48710007af82a68da0007c820f2 (patch)
tree7f4f2504207970dcbea2f69b2fad5c9a5ec62743
parent638d0cb7531525201e00577d5a77f1da3f84811e (diff)
downloadphp-git-4638f7b91407c48710007af82a68da0007c820f2.tar.gz
Change "foreach" statement behavior (this is just a PoC yet)
- "foreach by value" don't relay on internal array/object pointer and doesnt perform array duplication. It just locks it incrementing reference counter. If the original array is modified by some code, the copy on write is performed and "foreach" still work with the old copy. - it makes no difference if array given to "foreach by value" is reference itself - "foreach by reference" still use internal array/object pointer and should work similar to PHP-5. (This id not completely implemented)
-rw-r--r--Zend/tests/bug40509.phpt2
-rw-r--r--Zend/tests/bug40705.phpt2
-rw-r--r--Zend/zend_compile.c22
-rw-r--r--Zend/zend_compile.h3
-rw-r--r--Zend/zend_hash.h7
-rw-r--r--Zend/zend_opcode.c6
-rw-r--r--Zend/zend_types.h4
-rw-r--r--Zend/zend_vm_def.h615
-rw-r--r--Zend/zend_vm_execute.h1451
-rw-r--r--Zend/zend_vm_opcodes.c8
-rw-r--r--Zend/zend_vm_opcodes.h6
-rw-r--r--ext/opcache/Optimizer/block_pass.c14
-rw-r--r--ext/opcache/Optimizer/nop_removal.c6
-rw-r--r--ext/opcache/Optimizer/optimize_temp_vars_5.c35
-rw-r--r--ext/opcache/Optimizer/pass1_5.c6
-rw-r--r--ext/opcache/Optimizer/pass3.c6
-rw-r--r--ext/opcache/Optimizer/zend_optimizer.c12
-rw-r--r--ext/opcache/zend_persist.c6
-rw-r--r--tests/lang/bug23624.phpt2
-rw-r--r--tests/lang/foreachLoop.001.phpt2
-rw-r--r--tests/lang/foreachLoop.009.phpt6
-rw-r--r--tests/lang/foreachLoop.011.phpt7
-rw-r--r--tests/lang/foreachLoop.014.phpt139
-rw-r--r--tests/lang/foreachLoopObjects.006.phpt32
24 files changed, 1226 insertions, 1173 deletions
diff --git a/Zend/tests/bug40509.phpt b/Zend/tests/bug40509.phpt
index 21eaae9444..65e32533ef 100644
--- a/Zend/tests/bug40509.phpt
+++ b/Zend/tests/bug40509.phpt
@@ -23,4 +23,4 @@ var_dump(key($arr["v"]));
int(0)
int(0)
int(0)
-NULL
+int(0)
diff --git a/Zend/tests/bug40705.phpt b/Zend/tests/bug40705.phpt
index 374f73b75e..8a679654d5 100644
--- a/Zend/tests/bug40705.phpt
+++ b/Zend/tests/bug40705.phpt
@@ -23,4 +23,4 @@ int(0)
int(0)
int(1)
int(2)
-NULL
+int(0)
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index 7476d475de..e37fdd778c 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -3396,30 +3396,22 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */
}
opnum_reset = get_next_op_number(CG(active_op_array));
- opline = zend_emit_op(&reset_node, ZEND_FE_RESET, &expr_node, NULL);
- if (by_ref && is_variable) {
- opline->extended_value = ZEND_FE_FETCH_BYREF;
- }
+ opline = zend_emit_op(&reset_node, by_ref ? ZEND_FE_RESET_RW : ZEND_FE_RESET_R, &expr_node, NULL);
zend_stack_push(&CG(loop_var_stack), &reset_node);
opnum_fetch = get_next_op_number(CG(active_op_array));
- opline = zend_emit_op(&value_node, ZEND_FE_FETCH, &reset_node, NULL);
- if (by_ref) {
- opline->extended_value |= ZEND_FE_FETCH_BYREF;
- }
+ opline = zend_emit_op(&value_node, by_ref ? ZEND_FE_FETCH_RW : ZEND_FE_FETCH_R, &reset_node, NULL);
if (key_ast) {
- opline->extended_value |= ZEND_FE_FETCH_WITH_KEY;
+ opline->extended_value = 1;
}
opline = zend_emit_op(NULL, ZEND_OP_DATA, NULL, NULL);
- /* Allocate enough space to keep HashPointer on VM stack */
- opline->op1_type = IS_TMP_VAR;
- opline->op1.var = get_temporary_variable(CG(active_op_array));
- if (sizeof(HashPointer) > sizeof(zval)) {
- /* Make sure 1 zval is enough for HashPointer (2 must be enough) */
- get_temporary_variable(CG(active_op_array));
+ if (by_ref) {
+ /* Allocate temporary variable to keep HashTable value */
+ opline->op1_type = IS_TMP_VAR;
+ opline->op1.var = get_temporary_variable(CG(active_op_array));
}
if (key_ast) {
diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h
index 7c82c67d6d..2d71ca2571 100644
--- a/Zend/zend_compile.h
+++ b/Zend/zend_compile.h
@@ -828,9 +828,6 @@ int zend_add_literal(zend_op_array *op_array, zval *zv);
#define ZEND_FETCH_ARG_MASK 0x000fffff
-#define ZEND_FE_FETCH_BYREF 1
-#define ZEND_FE_FETCH_WITH_KEY 2
-
#define EXT_TYPE_FREE_ON_RETURN (1<<2)
#define ZEND_MEMBER_FUNC_CALL 1<<0
diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h
index 377f508658..85f1890302 100644
--- a/Zend/zend_hash.h
+++ b/Zend/zend_hash.h
@@ -171,13 +171,6 @@ ZEND_API zval *zend_hash_get_current_data_ex(HashTable *ht, HashPosition *pos);
ZEND_API void zend_hash_internal_pointer_reset_ex(HashTable *ht, HashPosition *pos);
ZEND_API void zend_hash_internal_pointer_end_ex(HashTable *ht, HashPosition *pos);
-typedef struct _HashPointer {
- HashPosition pos;
- HashTable *ht;
- zend_ulong h;
- zend_string *key;
-} HashPointer;
-
#define zend_hash_has_more_elements(ht) \
zend_hash_has_more_elements_ex(ht, &(ht)->nInternalPointer)
#define zend_hash_move_forward(ht) \
diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c
index a6d041f131..c1e3adb3ec 100644
--- a/Zend/zend_opcode.c
+++ b/Zend/zend_opcode.c
@@ -766,8 +766,10 @@ ZEND_API int pass_two(zend_op_array *op_array)
case ZEND_JMP_SET:
case ZEND_COALESCE:
case ZEND_NEW:
- case ZEND_FE_RESET:
- case ZEND_FE_FETCH:
+ case ZEND_FE_RESET_R:
+ case ZEND_FE_RESET_RW:
+ case ZEND_FE_FETCH_R:
+ case ZEND_FE_FETCH_RW:
ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op2);
break;
case ZEND_VERIFY_RETURN_TYPE:
diff --git a/Zend/zend_types.h b/Zend/zend_types.h
index 5c00cb133f..aa5404139b 100644
--- a/Zend/zend_types.h
+++ b/Zend/zend_types.h
@@ -128,6 +128,7 @@ struct _zval_struct {
uint32_t cache_slot; /* literal cache slot */
uint32_t lineno; /* line number (for ast nodes) */
uint32_t num_args; /* arguments number for EX(This) */
+ uint32_t fe_pos; /* foreach position */
} u2;
};
@@ -261,6 +262,9 @@ static zend_always_inline zend_uchar zval_get_type(const zval* pz) {
#define Z_CACHE_SLOT(zval) (zval).u2.cache_slot
#define Z_CACHE_SLOT_P(zval_p) Z_CACHE_SLOT(*(zval_p))
+#define Z_FE_POS(zval) (zval).u2.fe_pos
+#define Z_FE_POS_P(zval_p) Z_FE_POS(*(zval_p))
+
#define Z_COUNTED(zval) (zval).value.counted
#define Z_COUNTED_P(zval_p) Z_COUNTED(*(zval_p))
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index 24bb3fd3d6..aae951eeed 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -4620,292 +4620,405 @@ ZEND_VM_HANDLER(76, ZEND_UNSET_OBJ, VAR|UNUSED|CV, CONST|TMPVAR|CV)
ZEND_VM_NEXT_OPCODE();
}
-ZEND_VM_HANDLER(77, ZEND_FE_RESET, CONST|TMP|VAR|CV, ANY)
+ZEND_VM_HANDLER(77, ZEND_FE_RESET_R, CONST|TMP|VAR|CV, ANY)
{
USE_OPLINE
zend_free_op free_op1;
- zval *array_ptr, *array_ref, iterator, tmp;
+ zval *array_ptr;
HashTable *fe_ht;
- zend_object_iterator *iter = NULL;
- zend_class_entry *ce = NULL;
- zend_bool is_empty = 0;
SAVE_OPLINE();
- if ((OP1_TYPE == IS_CV || OP1_TYPE == IS_VAR) &&
- (opline->extended_value & ZEND_FE_FETCH_BYREF)) {
- array_ptr = array_ref = GET_OP1_ZVAL_PTR_PTR(BP_VAR_R);
- ZVAL_DEREF(array_ptr);
- if (Z_TYPE_P(array_ptr) == IS_ARRAY) {
- SEPARATE_ARRAY(array_ptr);
- if (!Z_ISREF_P(array_ref)) {
- ZVAL_NEW_REF(array_ref, array_ref);
- array_ptr = Z_REFVAL_P(array_ref);
- }
- if (Z_REFCOUNTED_P(array_ref)) Z_ADDREF_P(array_ref);
- } else if (Z_TYPE_P(array_ptr) == IS_OBJECT) {
- ce = Z_OBJCE_P(array_ptr);
- if (ce->get_iterator == NULL) {
- Z_ADDREF_P(array_ptr);
+ array_ptr = GET_OP1_ZVAL_PTR(BP_VAR_R);
+ ZVAL_DEREF(array_ptr);
+ 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 (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
+ FREE_OP1_IF_VAR();
+ if (!EG(exception)) {
+ zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
}
- array_ref = array_ptr;
- } else {
- if (Z_REFCOUNTED_P(array_ref)) Z_ADDREF_P(array_ref);
- }
- } else {
- array_ptr = array_ref = GET_OP1_ZVAL_PTR(BP_VAR_R);
- if (OP1_TYPE & (IS_VAR|IS_CV)) {
- ZVAL_DEREF(array_ptr);
+ zend_throw_exception_internal(NULL);
+ HANDLE_EXCEPTION();
}
- if (OP1_TYPE == IS_TMP_VAR) {
- ZVAL_COPY_VALUE(&tmp, array_ptr);
- if (Z_OPT_IMMUTABLE_P(&tmp)) {
- zval_copy_ctor_func(&tmp);
- }
- array_ref = array_ptr = &tmp;
- if (Z_TYPE_P(array_ptr) == IS_OBJECT) {
- ce = Z_OBJCE_P(array_ptr);
- if (ce && ce->get_iterator) {
- Z_DELREF_P(array_ref);
- }
- }
- } else if (Z_TYPE_P(array_ptr) == IS_OBJECT) {
- ce = Z_OBJCE_P(array_ptr);
- if (!ce->get_iterator) {
- if (OP1_TYPE == IS_CV) {
- Z_ADDREF_P(array_ref);
- }
+
+ iter->index = 0;
+ if (iter->funcs->rewind) {
+ iter->funcs->rewind(iter);
+ if (UNEXPECTED(EG(exception) != NULL)) {
+ FREE_OP1_IF_VAR();
+ OBJ_RELEASE(&iter->std);
+ HANDLE_EXCEPTION();
}
- } else if (Z_IMMUTABLE_P(array_ref)) {
- if (OP1_TYPE == IS_CV) {
- zval_copy_ctor_func(array_ref);
- Z_ADDREF_P(array_ref);
- } else {
- ZVAL_COPY_VALUE(&tmp, array_ref);
- zval_copy_ctor_func(&tmp);
- array_ptr = array_ref = &tmp;
- }
- } else if (Z_REFCOUNTED_P(array_ref)) {
- if (OP1_TYPE == IS_CONST ||
- (OP1_TYPE == IS_CV &&
- !Z_ISREF_P(array_ref) &&
- Z_REFCOUNT_P(array_ref) > 1) ||
- (OP1_TYPE == IS_VAR &&
- !Z_ISREF_P(array_ref) &&
- Z_REFCOUNT_P(array_ref) > 2)) {
- if (OP1_TYPE == IS_VAR) {
- Z_DELREF_P(array_ref);
- }
- ZVAL_DUP(&tmp, array_ref);
- array_ptr = array_ref = &tmp;
- } else if (OP1_TYPE == IS_CV || OP1_TYPE == IS_VAR) {
- if (Z_ISREF_P(array_ref) && Z_REFCOUNT_P(array_ref) == 1) {
- ZVAL_UNREF(array_ref);
- array_ptr = array_ref;
- }
- if (Z_IMMUTABLE_P(array_ptr)) {
- zval_copy_ctor_func(array_ptr);
- } else if (Z_ISREF_P(array_ref) &&
- Z_COPYABLE_P(array_ptr) &&
- Z_REFCOUNT_P(array_ptr) > 1) {
- Z_DELREF_P(array_ptr);
- zval_copy_ctor_func(array_ptr);
- }
- if (OP1_TYPE == IS_CV) {
- Z_ADDREF_P(array_ref);
- }
+ }
+
+ is_empty = iter->funcs->valid(iter) != SUCCESS;
+
+ if (UNEXPECTED(EG(exception) != NULL)) {
+ FREE_OP1_IF_VAR();
+ OBJ_RELEASE(&iter->std);
+ HANDLE_EXCEPTION();
+ }
+ iter->index = -1; /* will be set to 0 before using next handler */
+
+ ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
+
+ FREE_OP1_IF_VAR();
+ 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) {
+ if (OP1_TYPE != IS_TMP_VAR) {
+ if (Z_REFCOUNTED_P(array_ptr)) {
+ Z_ADDREF_P(array_ptr);
}
}
+ ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ptr);
+ Z_FE_POS_P(EX_VAR(opline->result.var)) = 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));
+ FREE_OP1();
+ ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
}
+}
- if (ce && ce->get_iterator) {
- iter = ce->get_iterator(ce, array_ptr, opline->extended_value & ZEND_FE_FETCH_BYREF);
+ZEND_VM_HANDLER(125, ZEND_FE_RESET_RW, CONST|TMP|VAR|CV, ANY)
+{
+ USE_OPLINE
+ zend_free_op free_op1;
+ zval *array_ptr, *array_ref;
+ HashTable *fe_ht;
- if (OP1_TYPE == IS_VAR && !(opline->extended_value & ZEND_FE_FETCH_BYREF)) {
- FREE_OP1_IF_VAR();
+ SAVE_OPLINE();
+
+ if (OP1_TYPE == IS_VAR || OP1_TYPE == IS_CV) {
+ array_ref = GET_OP1_ZVAL_PTR_PTR(BP_VAR_R);
+ ZVAL_MAKE_REF(array_ref);
+ array_ptr = Z_REFVAL_P(array_ref);
+ if (Z_TYPE_P(array_ptr) == IS_ARRAY) {
+ SEPARATE_ARRAY(array_ptr);
}
- if (iter && EXPECTED(EG(exception) == NULL)) {
- ZVAL_OBJ(&iterator, &iter->std);
- array_ptr = array_ref = &iterator;
- } else {
- if (OP1_TYPE == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
- FREE_OP1_VAR_PTR();
- }
+ } else {
+ 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))) {
+ FREE_OP1_VAR_PTR();
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();
}
- }
- ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref);
-
- if (iter) {
iter->index = 0;
if (iter->funcs->rewind) {
iter->funcs->rewind(iter);
if (UNEXPECTED(EG(exception) != NULL)) {
- zval_ptr_dtor(array_ref);
- if (OP1_TYPE == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
- FREE_OP1_VAR_PTR();
- }
+ FREE_OP1_VAR_PTR();
+ OBJ_RELEASE(&iter->std);
HANDLE_EXCEPTION();
}
}
+
is_empty = iter->funcs->valid(iter) != SUCCESS;
+
if (UNEXPECTED(EG(exception) != NULL)) {
- zval_ptr_dtor(array_ref);
- if (OP1_TYPE == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
- FREE_OP1_VAR_PTR();
- }
+ FREE_OP1_VAR_PTR();
+ OBJ_RELEASE(&iter->std);
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_POS_P(EX_VAR(opline->result.var)) = INVALID_IDX;
+ ZVAL_PTR(EX_VAR((opline+2)->op1.var), NULL);
+
+ FREE_OP1_VAR_PTR();
+ 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) {
- HashPointer *ptr = (HashPointer*)EX_VAR((opline+2)->op1.var);
HashPosition pos = 0;
Bucket *p;
+ if (OP1_TYPE != IS_TMP_VAR) {
+ if (Z_REFCOUNTED_P(array_ref)) {
+ Z_ADDREF_P(array_ref);
+ }
+ }
+ ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref);
while (1) {
if (pos >= fe_ht->nNumUsed) {
- is_empty = 1;
- if (OP1_TYPE == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
- FREE_OP1_VAR_PTR();
- }
+ FREE_OP1_VAR_PTR();
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)) {
- pos++;
- continue;
- }
- if (!ce ||
- !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)) &&
+ (Z_TYPE_P(array_ptr) != IS_OBJECT ||
+ !p->key ||
+ zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
break;
}
pos++;
}
- fe_ht->nInternalPointer = pos;
- ptr->pos = pos;
- ptr->ht = fe_ht;
- ptr->h = fe_ht->arData[pos].h;
- ptr->key = fe_ht->arData[pos].key;
- is_empty = 0;
- } else {
- zend_error(E_WARNING, "Invalid argument supplied for foreach()");
- is_empty = 1;
- }
+ Z_FE_POS_P(EX_VAR(opline->result.var)) = fe_ht->nInternalPointer = pos;
+ ZVAL_PTR(EX_VAR((opline+2)->op1.var), fe_ht);
- if (OP1_TYPE == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
FREE_OP1_VAR_PTR();
- }
- 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));
+ FREE_OP1_VAR_PTR();
+ ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
}
}
-ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY)
+ZEND_VM_HANDLER(78, ZEND_FE_FETCH_R, VAR, ANY)
{
USE_OPLINE
zend_free_op free_op1;
- zval *array, *array_ref;
+ zval *array;
zval *value;
HashTable *fe_ht;
- HashPointer *ptr;
HashPosition pos;
Bucket *p;
- array = array_ref = EX_VAR(opline->op1.var);
- if (Z_ISREF_P(array)) {
- array = Z_REFVAL_P(array);
- // TODO: referenced value might be changed to different array ???
- if (Z_IMMUTABLE_P(array)) {
- zval_copy_ctor_func(array);
+ array = EX_VAR(opline->op1.var);
+ SAVE_OPLINE();
+ if (EXPECTED(Z_TYPE_P(array) == IS_ARRAY)) {
+ fe_ht = Z_ARRVAL_P(array);
+ pos = Z_FE_POS_P(EX_VAR(opline->op1.var));
+ while (1) {
+ if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
+ /* reached end of iteration */
+ ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+ }
+ p = fe_ht->arData + pos;
+ value = &p->val;
+ if (Z_TYPE_P(value) == IS_UNDEF) {
+ pos++;
+ continue;
+ } else if (Z_TYPE_P(value) == IS_INDIRECT) {
+ value = Z_INDIRECT_P(value);
+ if (Z_TYPE_P(value) == IS_UNDEF) {
+ pos++;
+ continue;
+ }
+ }
+ break;
}
+ if (opline->extended_value) {
+ if (!p->key) {
+ ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
+ } else {
+ ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
+ }
+ }
+ ZVAL_COPY(EX_VAR(opline->result.var), value);
+ Z_FE_POS_P(EX_VAR(opline->op1.var)) = pos + 1;
+ ZEND_VM_INC_OPCODE();
+ ZEND_VM_NEXT_OPCODE();
+ } else if (EXPECTED(Z_TYPE_P(array) == IS_OBJECT)) {
+ zend_object_iterator *iter;
+
+ if ((iter = zend_iterator_unwrap(array)) == NULL) {
+ /* plain object */
+ zend_object *zobj = Z_OBJ_P(array);
+
+ fe_ht = Z_OBJPROP_P(array);
+ pos = Z_FE_POS_P(EX_VAR(opline->op1.var));
+ while (1) {
+ if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
+ /* reached end of iteration */
+ ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+ }
+
+ p = fe_ht->arData + pos;
+ value = &p->val;
+ if (Z_TYPE_P(value) == IS_UNDEF) {
+ pos++;
+ continue;
+ } else if (Z_TYPE_P(value) == IS_INDIRECT) {
+ value = Z_INDIRECT_P(value);
+ if (Z_TYPE_P(value) == IS_UNDEF) {
+ pos++;
+ continue;
+ }
+ }
+ if (!p->key ||
+ zend_check_property_access(Z_OBJ_P(array), p->key) == SUCCESS) {
+ break;
+ }
+ pos++;
+ }
+ if (opline->extended_value) {
+ if (UNEXPECTED(!p->key)) {
+ ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
+ } else if (p->key->val[0]) {
+ ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
+ } else {
+ const char *class_name, *prop_name;
+ size_t prop_name_len;
+ zend_unmangle_property_name_ex(
+ p->key, &class_name, &prop_name, &prop_name_len);
+ ZVAL_STRINGL(EX_VAR((opline+1)->result.var), prop_name, prop_name_len);
+ }
+ }
+ ZVAL_COPY(EX_VAR(opline->result.var), value);
+ Z_FE_POS_P(EX_VAR(opline->op1.var)) = pos + 1;
+ ZEND_VM_INC_OPCODE();
+ ZEND_VM_NEXT_OPCODE();
+ } else {
+ /* !iter happens from exception */
+ if (iter && ++iter->index > 0) {
+ /* This could cause an endless loop if index becomes zero again.
+ * In case that ever happens we need an additional flag. */
+ iter->funcs->move_forward(iter);
+ if (UNEXPECTED(EG(exception) != NULL)) {
+ zval_ptr_dtor(array);
+ HANDLE_EXCEPTION();
+ }
+ }
+ /* If index is zero we come from FE_RESET and checked valid() already. */
+ if (!iter || (iter->index > 0 && iter->funcs->valid(iter) == FAILURE)) {
+ /* reached end of iteration */
+ if (UNEXPECTED(EG(exception) != NULL)) {
+ zval_ptr_dtor(array);
+ HANDLE_EXCEPTION();
+ }
+ ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+ }
+ value = iter->funcs->get_current_data(iter);
+ if (UNEXPECTED(EG(exception) != NULL)) {
+ zval_ptr_dtor(array);
+ HANDLE_EXCEPTION();
+ }
+ if (!value) {
+ /* failure in get_current_data */
+ ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+ }
+ ZVAL_COPY(EX_VAR(opline->result.var), value);
+ if (opline->extended_value) {
+ if (iter->funcs->get_current_key) {
+ iter->funcs->get_current_key(iter, EX_VAR((opline+1)->result.var));
+ if (UNEXPECTED(EG(exception) != NULL)) {
+ zval_ptr_dtor(array);
+ HANDLE_EXCEPTION();
+ }
+ } else {
+ ZVAL_LONG(EX_VAR((opline+1)->result.var), iter->index);
+ }
+ }
+ ZEND_VM_INC_OPCODE();
+ ZEND_VM_NEXT_OPCODE();
+ }
+ } else {
+ zend_error(E_WARNING, "Invalid argument supplied for foreach()");
+ ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
}
+}
+ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY)
+{
+ USE_OPLINE
+ zend_free_op free_op1;
+ zval *array;
+ zval *value;
+ HashTable *fe_ht;
+ HashPosition pos;
+ Bucket *p;
+
+ array = EX_VAR(opline->op1.var);
SAVE_OPLINE();
+ ZVAL_DEREF(array);
if (EXPECTED(Z_TYPE_P(array) == IS_ARRAY)) {
fe_ht = Z_ARRVAL_P(array);
- ptr = (HashPointer*)EX_VAR((opline+1)->op1.var);
- pos = ptr->pos;
+ pos = Z_FE_POS_P(EX_VAR(opline->op1.var));
if (UNEXPECTED(pos == INVALID_IDX)) {
/* reached end of iteration */
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
- } else if (UNEXPECTED(ptr->ht != fe_ht)) {
- ptr->ht = fe_ht;
- pos = 0;
- } else if (UNEXPECTED(fe_ht->nInternalPointer != ptr->pos)) {
- if (fe_ht->u.flags & HASH_FLAG_PACKED) {
- pos = ptr->h;
- } else {
- pos = fe_ht->arHash[ptr->h & fe_ht->nTableMask];
- while (1) {
- if (pos == INVALID_IDX) {
- pos = fe_ht->nInternalPointer;
- break;
- } else if (fe_ht->arData[pos].h == ptr->h && fe_ht->arData[pos].key == ptr->key) {
- break;
- }
- pos = Z_NEXT(fe_ht->arData[pos].val);
- }
+ } else {
+ if (Z_PTR_P(EX_VAR((opline+1)->op1.var)) != fe_ht) {
+ pos = fe_ht->nInternalPointer;
}
+ SEPARATE_ARRAY(array);
+ fe_ht = Z_ARRVAL_P(array);
+ Z_PTR_P(EX_VAR((opline+1)->op1.var)) = fe_ht;
}
+//??? if (pos != fe_ht->nInternalPointer) {
+//??? //...
+//??? }
while (1) {
if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
/* reached end of iteration */
+ fe_ht->nInternalPointer = INVALID_IDX;
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
}
p = fe_ht->arData + pos;
value = &p->val;
- if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
+ if (Z_TYPE_P(value) == IS_UNDEF) {
pos++;
continue;
- } else if (UNEXPECTED(Z_TYPE_P(value) == IS_INDIRECT)) {
+ } else if (Z_TYPE_P(value) == IS_INDIRECT) {
value = Z_INDIRECT_P(value);
- if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
+ if (Z_TYPE_P(value) == IS_UNDEF) {
pos++;
continue;
}
}
- if (opline->extended_value & ZEND_FE_FETCH_BYREF) {
- ZVAL_MAKE_REF(value);
- Z_ADDREF_P(value);
- ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
+ break;
+ }
+ if (opline->extended_value) {
+ if (!p->key) {
+ ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
} else {
- ZVAL_COPY(EX_VAR(opline->result.var), value);
+ ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
}
- if (opline->extended_value & ZEND_FE_FETCH_WITH_KEY) {
- if (!p->key) {
- ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
- } else {
- ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
- }
- }
- break;
}
- do {
+ ZVAL_MAKE_REF(value);
+ Z_ADDREF_P(value);
+ ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
+ while (1) {
pos++;
if (pos >= fe_ht->nNumUsed) {
- fe_ht->nInternalPointer = ptr->pos = INVALID_IDX;
- ZEND_VM_INC_OPCODE();
- ZEND_VM_NEXT_OPCODE();
+ pos = INVALID_IDX;
+ break;
}
p = fe_ht->arData + pos;
- } while (Z_TYPE(p->val) == IS_UNDEF ||
- (Z_TYPE(p->val) == IS_INDIRECT &&
- Z_TYPE_P(Z_INDIRECT(p->val)) == IS_UNDEF));
- fe_ht->nInternalPointer = ptr->pos = pos;
- ptr->h = fe_ht->arData[pos].h;
- ptr->key = fe_ht->arData[pos].key;
+ if (Z_TYPE(p->val) != IS_UNDEF &&
+ (Z_TYPE(p->val) != IS_INDIRECT ||
+ Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) {
+ break;
+ }
+ }
+ Z_FE_POS_P(EX_VAR(opline->op1.var)) = fe_ht->nInternalPointer = pos;
ZEND_VM_INC_OPCODE();
ZEND_VM_NEXT_OPCODE();
} else if (EXPECTED(Z_TYPE_P(array) == IS_OBJECT)) {
@@ -4916,93 +5029,77 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY)
zend_object *zobj = Z_OBJ_P(array);
fe_ht = Z_OBJPROP_P(array);
- ptr = (HashPointer*)EX_VAR((opline+1)->op1.var);
- pos = ptr->pos;
- if (pos == INVALID_IDX) {
+ pos = Z_FE_POS_P(EX_VAR(opline->op1.var));
+ if (UNEXPECTED(pos == INVALID_IDX)) {
/* reached end of iteration */
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
- } else if (UNEXPECTED(ptr->ht != fe_ht)) {
- ptr->ht = fe_ht;
- pos = 0;
- } else if (UNEXPECTED(fe_ht->nInternalPointer != ptr->pos)) {
- if (fe_ht->u.flags & HASH_FLAG_PACKED) {
- pos = ptr->h;
- } else {
- pos = fe_ht->arHash[ptr->h & fe_ht->nTableMask];
- while (1) {
- if (pos == INVALID_IDX) {
- pos = fe_ht->nInternalPointer;
- break;
- } else if (fe_ht->arData[pos].h == ptr->h && fe_ht->arData[pos].key == ptr->key) {
- break;
- }
- pos = Z_NEXT(fe_ht->arData[pos].val);
- }
+ } else {
+ if (Z_PTR_P(EX_VAR((opline+1)->op1.var)) != fe_ht) {
+ pos = fe_ht->nInternalPointer;
}
+ Z_PTR_P(EX_VAR((opline+1)->op1.var)) = fe_ht;
}
+//??? if (pos != fe_ht->nInternalPointer) {
+//???
+//??? }
while (1) {
if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
/* reached end of iteration */
+ fe_ht->nInternalPointer = INVALID_IDX;
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
}
p = fe_ht->arData + pos;
value = &p->val;
- if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
+ if (Z_TYPE_P(value) == IS_UNDEF) {
pos++;
continue;
- } else if (UNEXPECTED(Z_TYPE_P(value) == IS_INDIRECT)) {
+ } else if (Z_TYPE_P(value) == IS_INDIRECT) {
value = Z_INDIRECT_P(value);
- if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
+ if (Z_TYPE_P(value) == IS_UNDEF) {
pos++;
continue;
}
}
-
- if (UNEXPECTED(!p->key)) {
- if (opline->extended_value & ZEND_FE_FETCH_WITH_KEY) {
- ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
- }
- break;
- } else if (zend_check_property_access(zobj, p->key) == SUCCESS) {
- if (opline->extended_value & ZEND_FE_FETCH_WITH_KEY) {
- if (p->key->val[0]) {
- ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
- } else {
- const char *class_name, *prop_name;
- size_t prop_name_len;
- zend_unmangle_property_name_ex(
- p->key, &class_name, &prop_name, &prop_name_len);
- ZVAL_STRINGL(EX_VAR((opline+1)->result.var), prop_name, prop_name_len);
- }
- }
+ if (!p->key ||
+ zend_check_property_access(Z_OBJ_P(array), p->key) == SUCCESS) {
break;
}
pos++;
}
- if (opline->extended_value & ZEND_FE_FETCH_BYREF) {
- ZVAL_MAKE_REF(value);
- Z_ADDREF_P(value);
- ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
- } else {
- ZVAL_COPY(EX_VAR(opline->result.var), value);
+ if (opline->extended_value) {
+ if (UNEXPECTED(!p->key)) {
+ ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
+ } else if (p->key->val[0]) {
+ ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
+ } else {
+ const char *class_name, *prop_name;
+ size_t prop_name_len;
+ zend_unmangle_property_name_ex(
+ p->key, &class_name, &prop_name, &prop_name_len);
+ ZVAL_STRINGL(EX_VAR((opline+1)->result.var), prop_name, prop_name_len);
+ }
}
- do {
+ ZVAL_MAKE_REF(value);
+ Z_ADDREF_P(value);
+ ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
+ while (1) {
pos++;
if (pos >= fe_ht->nNumUsed) {
- fe_ht->nInternalPointer = ptr->pos = INVALID_IDX;
- ZEND_VM_INC_OPCODE();
- ZEND_VM_NEXT_OPCODE();
+ pos = INVALID_IDX;
+ break;
}
p = fe_ht->arData + pos;
- } while (Z_TYPE(p->val) == IS_UNDEF ||
- (Z_TYPE(p->val) == IS_INDIRECT &&
- Z_TYPE_P(Z_INDIRECT(p->val)) == IS_UNDEF) ||
- (EXPECTED(p->key != NULL) &&
- zend_check_property_access(zobj, p->key) == FAILURE));
- fe_ht->nInternalPointer = ptr->pos = pos;
- ptr->h = fe_ht->arData[pos].h;
- ptr->key = fe_ht->arData[pos].key;
+ 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;
+ }
+ }
+ Z_FE_POS_P(EX_VAR(opline->op1.var)) = fe_ht->nInternalPointer = pos;
ZEND_VM_INC_OPCODE();
ZEND_VM_NEXT_OPCODE();
} else {
@@ -5012,7 +5109,7 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY)
* In case that ever happens we need an additional flag. */
iter->funcs->move_forward(iter);
if (UNEXPECTED(EG(exception) != NULL)) {
- zval_ptr_dtor(array_ref);
+ zval_ptr_dtor(array);
HANDLE_EXCEPTION();
}
}
@@ -5020,32 +5117,28 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY)
if (!iter || (iter->index > 0 && iter->funcs->valid(iter) == FAILURE)) {
/* reached end of iteration */
if (UNEXPECTED(EG(exception) != NULL)) {
- zval_ptr_dtor(array_ref);
+ zval_ptr_dtor(array);
HANDLE_EXCEPTION();
}
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
}
value = iter->funcs->get_current_data(iter);
if (UNEXPECTED(EG(exception) != NULL)) {
- zval_ptr_dtor(array_ref);
+ zval_ptr_dtor(array);
HANDLE_EXCEPTION();
}
if (!value) {
/* failure in get_current_data */
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
}
- if (opline->extended_value & ZEND_FE_FETCH_BYREF) {
- ZVAL_MAKE_REF(value);
- Z_ADDREF_P(value);
- ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
- } else {
- ZVAL_COPY(EX_VAR(opline->result.var), value);
- }
- if (opline->extended_value & ZEND_FE_FETCH_WITH_KEY) {
+ ZVAL_MAKE_REF(value);
+ Z_ADDREF_P(value);
+ ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
+ if (opline->extended_value) {
if (iter->funcs->get_current_key) {
iter->funcs->get_current_key(iter, EX_VAR((opline+1)->result.var));
if (UNEXPECTED(EG(exception) != NULL)) {
- zval_ptr_dtor(array_ref);
+ zval_ptr_dtor(array);
HANDLE_EXCEPTION();
}
} else {
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index 9a7b23d87a..a51941195c 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -3039,194 +3039,178 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HA
ZEND_VM_NEXT_OPCODE();
}
-static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+static int ZEND_FASTCALL ZEND_FE_RESET_R_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
- zval *array_ptr, *array_ref, iterator, tmp;
+ zval *array_ptr;
HashTable *fe_ht;
- zend_object_iterator *iter = NULL;
- zend_class_entry *ce = NULL;
- zend_bool is_empty = 0;
SAVE_OPLINE();
- if ((IS_CONST == IS_CV || IS_CONST == IS_VAR) &&
- (opline->extended_value & ZEND_FE_FETCH_BYREF)) {
- array_ptr = array_ref = NULL;
- ZVAL_DEREF(array_ptr);
- if (Z_TYPE_P(array_ptr) == IS_ARRAY) {
- SEPARATE_ARRAY(array_ptr);
- if (!Z_ISREF_P(array_ref)) {
- ZVAL_NEW_REF(array_ref, array_ref);
- array_ptr = Z_REFVAL_P(array_ref);
- }
- if (Z_REFCOUNTED_P(array_ref)) Z_ADDREF_P(array_ref);
- } else if (Z_TYPE_P(array_ptr) == IS_OBJECT) {
- ce = Z_OBJCE_P(array_ptr);
- if (ce->get_iterator == NULL) {
- Z_ADDREF_P(array_ptr);
+ array_ptr = EX_CONSTANT(opline->op1);
+ ZVAL_DEREF(array_ptr);
+ 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 (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);
}
- array_ref = array_ptr;
- } else {
- if (Z_REFCOUNTED_P(array_ref)) Z_ADDREF_P(array_ref);
- }
- } else {
- array_ptr = array_ref = EX_CONSTANT(opline->op1);
- if (IS_CONST & (IS_VAR|IS_CV)) {
- ZVAL_DEREF(array_ptr);
+ zend_throw_exception_internal(NULL);
+ HANDLE_EXCEPTION();
}
- if (IS_CONST == IS_TMP_VAR) {
- ZVAL_COPY_VALUE(&tmp, array_ptr);
- if (Z_OPT_IMMUTABLE_P(&tmp)) {
- zval_copy_ctor_func(&tmp);
- }
- array_ref = array_ptr = &tmp;
- if (Z_TYPE_P(array_ptr) == IS_OBJECT) {
- ce = Z_OBJCE_P(array_ptr);
- if (ce && ce->get_iterator) {
- Z_DELREF_P(array_ref);
- }
- }
- } else if (Z_TYPE_P(array_ptr) == IS_OBJECT) {
- ce = Z_OBJCE_P(array_ptr);
- if (!ce->get_iterator) {
- if (IS_CONST == IS_CV) {
- Z_ADDREF_P(array_ref);
- }
+
+ iter->index = 0;
+ if (iter->funcs->rewind) {
+ iter->funcs->rewind(iter);
+ if (UNEXPECTED(EG(exception) != NULL)) {
+
+ OBJ_RELEASE(&iter->std);
+ HANDLE_EXCEPTION();
}
- } else if (Z_IMMUTABLE_P(array_ref)) {
- if (IS_CONST == IS_CV) {
- zval_copy_ctor_func(array_ref);
- Z_ADDREF_P(array_ref);
- } else {
- ZVAL_COPY_VALUE(&tmp, array_ref);
- zval_copy_ctor_func(&tmp);
- array_ptr = array_ref = &tmp;
- }
- } else if (Z_REFCOUNTED_P(array_ref)) {
- if (IS_CONST == IS_CONST ||
- (IS_CONST == IS_CV &&
- !Z_ISREF_P(array_ref) &&
- Z_REFCOUNT_P(array_ref) > 1) ||
- (IS_CONST == IS_VAR &&
- !Z_ISREF_P(array_ref) &&
- Z_REFCOUNT_P(array_ref) > 2)) {
- if (IS_CONST == IS_VAR) {
- Z_DELREF_P(array_ref);
- }
- ZVAL_DUP(&tmp, array_ref);
- array_ptr = array_ref = &tmp;
- } else if (IS_CONST == IS_CV || IS_CONST == IS_VAR) {
- if (Z_ISREF_P(array_ref) && Z_REFCOUNT_P(array_ref) == 1) {
- ZVAL_UNREF(array_ref);
- array_ptr = array_ref;
- }
- if (Z_IMMUTABLE_P(array_ptr)) {
- zval_copy_ctor_func(array_ptr);
- } else if (Z_ISREF_P(array_ref) &&
- Z_COPYABLE_P(array_ptr) &&
- Z_REFCOUNT_P(array_ptr) > 1) {
- Z_DELREF_P(array_ptr);
- zval_copy_ctor_func(array_ptr);
- }
- if (IS_CONST == IS_CV) {
- Z_ADDREF_P(array_ref);
- }
+ }
+
+ is_empty = iter->funcs->valid(iter) != SUCCESS;
+
+ if (UNEXPECTED(EG(exception) != NULL)) {
+
+ OBJ_RELEASE(&iter->std);
+ HANDLE_EXCEPTION();
+ }
+ iter->index = -1; /* will be set to 0 before using next handler */
+
+ ZVAL_OBJ(EX_VAR(opline->result.var), &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) {
+ if (IS_CONST != IS_TMP_VAR) {
+ if (Z_REFCOUNTED_P(array_ptr)) {
+ Z_ADDREF_P(array_ptr);
}
}
+ ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ptr);
+ Z_FE_POS_P(EX_VAR(opline->result.var)) = 0;
+
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
+ } else {
+ zend_error(E_WARNING, "Invalid argument supplied for foreach()");
+ ZVAL_UNDEF(EX_VAR(opline->result.var));
+
+ ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
}
+}
- if (ce && ce->get_iterator) {
- iter = ce->get_iterator(ce, array_ptr, opline->extended_value & ZEND_FE_FETCH_BYREF);
+static int ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ USE_OPLINE
- if (IS_CONST == IS_VAR && !(opline->extended_value & ZEND_FE_FETCH_BYREF)) {
+ zval *array_ptr, *array_ref;
+ HashTable *fe_ht;
+ SAVE_OPLINE();
+
+ if (IS_CONST == IS_VAR || IS_CONST == IS_CV) {
+ array_ref = NULL;
+ ZVAL_MAKE_REF(array_ref);
+ array_ptr = Z_REFVAL_P(array_ref);
+ if (Z_TYPE_P(array_ptr) == IS_ARRAY) {
+ SEPARATE_ARRAY(array_ptr);
}
- if (iter && EXPECTED(EG(exception) == NULL)) {
- ZVAL_OBJ(&iterator, &iter->std);
- array_ptr = array_ref = &iterator;
- } else {
- if (IS_CONST == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
+ } else {
+ 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 (!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();
}
- }
- ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref);
-
- if (iter) {
iter->index = 0;
if (iter->funcs->rewind) {
iter->funcs->rewind(iter);
if (UNEXPECTED(EG(exception) != NULL)) {
- zval_ptr_dtor(array_ref);
- if (IS_CONST == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
- }
+ OBJ_RELEASE(&iter->std);
HANDLE_EXCEPTION();
}
}
+
is_empty = iter->funcs->valid(iter) != SUCCESS;
+
if (UNEXPECTED(EG(exception) != NULL)) {
- zval_ptr_dtor(array_ref);
- if (IS_CONST == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
- }
+ OBJ_RELEASE(&iter->std);
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_POS_P(EX_VAR(opline->result.var)) = INVALID_IDX;
+ ZVAL_PTR(EX_VAR((opline+2)->op1.var), NULL);
+
+ 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) {
- HashPointer *ptr = (HashPointer*)EX_VAR((opline+2)->op1.var);
HashPosition pos = 0;
Bucket *p;
+ if (IS_CONST != IS_TMP_VAR) {
+ if (Z_REFCOUNTED_P(array_ref)) {
+ Z_ADDREF_P(array_ref);
+ }
+ }
+ ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref);
while (1) {
if (pos >= fe_ht->nNumUsed) {
- is_empty = 1;
- if (IS_CONST == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
- }
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)) {
- pos++;
- continue;
- }
- if (!ce ||
- !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)) &&
+ (Z_TYPE_P(array_ptr) != IS_OBJECT ||
+ !p->key ||
+ zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
break;
}
pos++;
}
- fe_ht->nInternalPointer = pos;
- ptr->pos = pos;
- ptr->ht = fe_ht;
- ptr->h = fe_ht->arData[pos].h;
- ptr->key = fe_ht->arData[pos].key;
- is_empty = 0;
+ Z_FE_POS_P(EX_VAR(opline->result.var)) = fe_ht->nInternalPointer = pos;
+ ZVAL_PTR(EX_VAR((opline+2)->op1.var), fe_ht);
+
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
} else {
zend_error(E_WARNING, "Invalid argument supplied for foreach()");
- is_empty = 1;
- }
-
- if (IS_CONST == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
+ ZVAL_UNDEF(EX_VAR(opline->result.var));
- }
- if (is_empty) {
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
- } else {
- CHECK_EXCEPTION();
- ZEND_VM_NEXT_OPCODE();
}
}
@@ -8957,194 +8941,178 @@ static int ZEND_FASTCALL ZEND_CAST_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
ZEND_VM_NEXT_OPCODE();
}
-static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+static int ZEND_FASTCALL ZEND_FE_RESET_R_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
zend_free_op free_op1;
- zval *array_ptr, *array_ref, iterator, tmp;
+ zval *array_ptr;
HashTable *fe_ht;
- zend_object_iterator *iter = NULL;
- zend_class_entry *ce = NULL;
- zend_bool is_empty = 0;
SAVE_OPLINE();
- if ((IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) &&
- (opline->extended_value & ZEND_FE_FETCH_BYREF)) {
- array_ptr = array_ref = NULL;
- ZVAL_DEREF(array_ptr);
- if (Z_TYPE_P(array_ptr) == IS_ARRAY) {
- SEPARATE_ARRAY(array_ptr);
- if (!Z_ISREF_P(array_ref)) {
- ZVAL_NEW_REF(array_ref, array_ref);
- array_ptr = Z_REFVAL_P(array_ref);
- }
- if (Z_REFCOUNTED_P(array_ref)) Z_ADDREF_P(array_ref);
- } else if (Z_TYPE_P(array_ptr) == IS_OBJECT) {
- ce = Z_OBJCE_P(array_ptr);
- if (ce->get_iterator == NULL) {
- Z_ADDREF_P(array_ptr);
+ array_ptr = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1);
+ ZVAL_DEREF(array_ptr);
+ 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 (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);
}
- array_ref = array_ptr;
- } else {
- if (Z_REFCOUNTED_P(array_ref)) Z_ADDREF_P(array_ref);
- }
- } else {
- array_ptr = array_ref = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1);
- if (IS_TMP_VAR & (IS_VAR|IS_CV)) {
- ZVAL_DEREF(array_ptr);
+ zend_throw_exception_internal(NULL);
+ HANDLE_EXCEPTION();
}
- if (IS_TMP_VAR == IS_TMP_VAR) {
- ZVAL_COPY_VALUE(&tmp, array_ptr);
- if (Z_OPT_IMMUTABLE_P(&tmp)) {
- zval_copy_ctor_func(&tmp);
- }
- array_ref = array_ptr = &tmp;
- if (Z_TYPE_P(array_ptr) == IS_OBJECT) {
- ce = Z_OBJCE_P(array_ptr);
- if (ce && ce->get_iterator) {
- Z_DELREF_P(array_ref);
- }
- }
- } else if (Z_TYPE_P(array_ptr) == IS_OBJECT) {
- ce = Z_OBJCE_P(array_ptr);
- if (!ce->get_iterator) {
- if (IS_TMP_VAR == IS_CV) {
- Z_ADDREF_P(array_ref);
- }
+
+ iter->index = 0;
+ if (iter->funcs->rewind) {
+ iter->funcs->rewind(iter);
+ if (UNEXPECTED(EG(exception) != NULL)) {
+
+ OBJ_RELEASE(&iter->std);
+ HANDLE_EXCEPTION();
}
- } else if (Z_IMMUTABLE_P(array_ref)) {
- if (IS_TMP_VAR == IS_CV) {
- zval_copy_ctor_func(array_ref);
- Z_ADDREF_P(array_ref);
- } else {
- ZVAL_COPY_VALUE(&tmp, array_ref);
- zval_copy_ctor_func(&tmp);
- array_ptr = array_ref = &tmp;
- }
- } else if (Z_REFCOUNTED_P(array_ref)) {
- if (IS_TMP_VAR == IS_CONST ||
- (IS_TMP_VAR == IS_CV &&
- !Z_ISREF_P(array_ref) &&
- Z_REFCOUNT_P(array_ref) > 1) ||
- (IS_TMP_VAR == IS_VAR &&
- !Z_ISREF_P(array_ref) &&
- Z_REFCOUNT_P(array_ref) > 2)) {
- if (IS_TMP_VAR == IS_VAR) {
- Z_DELREF_P(array_ref);
- }
- ZVAL_DUP(&tmp, array_ref);
- array_ptr = array_ref = &tmp;
- } else if (IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) {
- if (Z_ISREF_P(array_ref) && Z_REFCOUNT_P(array_ref) == 1) {
- ZVAL_UNREF(array_ref);
- array_ptr = array_ref;
- }
- if (Z_IMMUTABLE_P(array_ptr)) {
- zval_copy_ctor_func(array_ptr);
- } else if (Z_ISREF_P(array_ref) &&
- Z_COPYABLE_P(array_ptr) &&
- Z_REFCOUNT_P(array_ptr) > 1) {
- Z_DELREF_P(array_ptr);
- zval_copy_ctor_func(array_ptr);
- }
- if (IS_TMP_VAR == IS_CV) {
- Z_ADDREF_P(array_ref);
- }
+ }
+
+ is_empty = iter->funcs->valid(iter) != SUCCESS;
+
+ if (UNEXPECTED(EG(exception) != NULL)) {
+
+ OBJ_RELEASE(&iter->std);
+ HANDLE_EXCEPTION();
+ }
+ iter->index = -1; /* will be set to 0 before using next handler */
+
+ ZVAL_OBJ(EX_VAR(opline->result.var), &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) {
+ if (IS_TMP_VAR != IS_TMP_VAR) {
+ if (Z_REFCOUNTED_P(array_ptr)) {
+ Z_ADDREF_P(array_ptr);
}
}
+ ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ptr);
+ Z_FE_POS_P(EX_VAR(opline->result.var)) = 0;
+
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
+ } else {
+ zend_error(E_WARNING, "Invalid argument supplied for foreach()");
+ ZVAL_UNDEF(EX_VAR(opline->result.var));
+ zval_ptr_dtor_nogc(free_op1);
+ ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
}
+}
- if (ce && ce->get_iterator) {
- iter = ce->get_iterator(ce, array_ptr, opline->extended_value & ZEND_FE_FETCH_BYREF);
+static int ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ USE_OPLINE
+ zend_free_op free_op1;
+ zval *array_ptr, *array_ref;
+ HashTable *fe_ht;
- if (IS_TMP_VAR == IS_VAR && !(opline->extended_value & ZEND_FE_FETCH_BYREF)) {
+ SAVE_OPLINE();
+ if (IS_TMP_VAR == IS_VAR || IS_TMP_VAR == IS_CV) {
+ array_ref = NULL;
+ ZVAL_MAKE_REF(array_ref);
+ array_ptr = Z_REFVAL_P(array_ref);
+ if (Z_TYPE_P(array_ptr) == IS_ARRAY) {
+ SEPARATE_ARRAY(array_ptr);
}
- if (iter && EXPECTED(EG(exception) == NULL)) {
- ZVAL_OBJ(&iterator, &iter->std);
- array_ptr = array_ref = &iterator;
- } else {
- if (IS_TMP_VAR == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
+ } else {
+ 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 (!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();
}
- }
- ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref);
-
- if (iter) {
iter->index = 0;
if (iter->funcs->rewind) {
iter->funcs->rewind(iter);
if (UNEXPECTED(EG(exception) != NULL)) {
- zval_ptr_dtor(array_ref);
- if (IS_TMP_VAR == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
- }
+ OBJ_RELEASE(&iter->std);
HANDLE_EXCEPTION();
}
}
+
is_empty = iter->funcs->valid(iter) != SUCCESS;
+
if (UNEXPECTED(EG(exception) != NULL)) {
- zval_ptr_dtor(array_ref);
- if (IS_TMP_VAR == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
- }
+ OBJ_RELEASE(&iter->std);
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_POS_P(EX_VAR(opline->result.var)) = INVALID_IDX;
+ ZVAL_PTR(EX_VAR((opline+2)->op1.var), NULL);
+
+ 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) {
- HashPointer *ptr = (HashPointer*)EX_VAR((opline+2)->op1.var);
HashPosition pos = 0;
Bucket *p;
+ if (IS_TMP_VAR != IS_TMP_VAR) {
+ if (Z_REFCOUNTED_P(array_ref)) {
+ Z_ADDREF_P(array_ref);
+ }
+ }
+ ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref);
while (1) {
if (pos >= fe_ht->nNumUsed) {
- is_empty = 1;
- if (IS_TMP_VAR == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
- }
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)) {
- pos++;
- continue;
- }
- if (!ce ||
- !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)) &&
+ (Z_TYPE_P(array_ptr) != IS_OBJECT ||
+ !p->key ||
+ zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
break;
}
pos++;
}
- fe_ht->nInternalPointer = pos;
- ptr->pos = pos;
- ptr->ht = fe_ht;
- ptr->h = fe_ht->arData[pos].h;
- ptr->key = fe_ht->arData[pos].key;
- is_empty = 0;
+ Z_FE_POS_P(EX_VAR(opline->result.var)) = fe_ht->nInternalPointer = pos;
+ ZVAL_PTR(EX_VAR((opline+2)->op1.var), fe_ht);
+
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
} else {
zend_error(E_WARNING, "Invalid argument supplied for foreach()");
- is_empty = 1;
- }
-
- if (IS_TMP_VAR == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
+ ZVAL_UNDEF(EX_VAR(opline->result.var));
- }
- if (is_empty) {
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
- } else {
- CHECK_EXCEPTION();
- ZEND_VM_NEXT_OPCODE();
}
}
@@ -11776,292 +11744,405 @@ static int ZEND_FASTCALL ZEND_CAST_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
ZEND_VM_NEXT_OPCODE();
}
-static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+static int ZEND_FASTCALL ZEND_FE_RESET_R_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
zend_free_op free_op1;
- zval *array_ptr, *array_ref, iterator, tmp;
+ zval *array_ptr;
HashTable *fe_ht;
- zend_object_iterator *iter = NULL;
- zend_class_entry *ce = NULL;
- zend_bool is_empty = 0;
SAVE_OPLINE();
- if ((IS_VAR == IS_CV || IS_VAR == IS_VAR) &&
- (opline->extended_value & ZEND_FE_FETCH_BYREF)) {
- array_ptr = array_ref = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1);
- ZVAL_DEREF(array_ptr);
- if (Z_TYPE_P(array_ptr) == IS_ARRAY) {
- SEPARATE_ARRAY(array_ptr);
- if (!Z_ISREF_P(array_ref)) {
- ZVAL_NEW_REF(array_ref, array_ref);
- array_ptr = Z_REFVAL_P(array_ref);
- }
- if (Z_REFCOUNTED_P(array_ref)) Z_ADDREF_P(array_ref);
- } else if (Z_TYPE_P(array_ptr) == IS_OBJECT) {
- ce = Z_OBJCE_P(array_ptr);
- if (ce->get_iterator == NULL) {
- Z_ADDREF_P(array_ptr);
+ array_ptr = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1);
+ ZVAL_DEREF(array_ptr);
+ 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 (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);
}
- array_ref = array_ptr;
- } else {
- if (Z_REFCOUNTED_P(array_ref)) Z_ADDREF_P(array_ref);
- }
- } else {
- array_ptr = array_ref = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1);
- if (IS_VAR & (IS_VAR|IS_CV)) {
- ZVAL_DEREF(array_ptr);
+ zend_throw_exception_internal(NULL);
+ HANDLE_EXCEPTION();
}
- if (IS_VAR == IS_TMP_VAR) {
- ZVAL_COPY_VALUE(&tmp, array_ptr);
- if (Z_OPT_IMMUTABLE_P(&tmp)) {
- zval_copy_ctor_func(&tmp);
- }
- array_ref = array_ptr = &tmp;
- if (Z_TYPE_P(array_ptr) == IS_OBJECT) {
- ce = Z_OBJCE_P(array_ptr);
- if (ce && ce->get_iterator) {
- Z_DELREF_P(array_ref);
- }
- }
- } else if (Z_TYPE_P(array_ptr) == IS_OBJECT) {
- ce = Z_OBJCE_P(array_ptr);
- if (!ce->get_iterator) {
- if (IS_VAR == IS_CV) {
- Z_ADDREF_P(array_ref);
- }
- }
- } else if (Z_IMMUTABLE_P(array_ref)) {
- if (IS_VAR == IS_CV) {
- zval_copy_ctor_func(array_ref);
- Z_ADDREF_P(array_ref);
- } else {
- ZVAL_COPY_VALUE(&tmp, array_ref);
- zval_copy_ctor_func(&tmp);
- array_ptr = array_ref = &tmp;
- }
- } else if (Z_REFCOUNTED_P(array_ref)) {
- if (IS_VAR == IS_CONST ||
- (IS_VAR == IS_CV &&
- !Z_ISREF_P(array_ref) &&
- Z_REFCOUNT_P(array_ref) > 1) ||
- (IS_VAR == IS_VAR &&
- !Z_ISREF_P(array_ref) &&
- Z_REFCOUNT_P(array_ref) > 2)) {
- if (IS_VAR == IS_VAR) {
- Z_DELREF_P(array_ref);
- }
- ZVAL_DUP(&tmp, array_ref);
- array_ptr = array_ref = &tmp;
- } else if (IS_VAR == IS_CV || IS_VAR == IS_VAR) {
- if (Z_ISREF_P(array_ref) && Z_REFCOUNT_P(array_ref) == 1) {
- ZVAL_UNREF(array_ref);
- array_ptr = array_ref;
- }
- if (Z_IMMUTABLE_P(array_ptr)) {
- zval_copy_ctor_func(array_ptr);
- } else if (Z_ISREF_P(array_ref) &&
- Z_COPYABLE_P(array_ptr) &&
- Z_REFCOUNT_P(array_ptr) > 1) {
- Z_DELREF_P(array_ptr);
- zval_copy_ctor_func(array_ptr);
- }
- if (IS_VAR == IS_CV) {
- Z_ADDREF_P(array_ref);
- }
+
+ iter->index = 0;
+ if (iter->funcs->rewind) {
+ iter->funcs->rewind(iter);
+ if (UNEXPECTED(EG(exception) != NULL)) {
+ zval_ptr_dtor_nogc(free_op1);
+ OBJ_RELEASE(&iter->std);
+ HANDLE_EXCEPTION();
}
}
- }
- if (ce && ce->get_iterator) {
- iter = ce->get_iterator(ce, array_ptr, opline->extended_value & ZEND_FE_FETCH_BYREF);
+ is_empty = iter->funcs->valid(iter) != SUCCESS;
- if (IS_VAR == IS_VAR && !(opline->extended_value & ZEND_FE_FETCH_BYREF)) {
+ if (UNEXPECTED(EG(exception) != NULL)) {
zval_ptr_dtor_nogc(free_op1);
+ OBJ_RELEASE(&iter->std);
+ HANDLE_EXCEPTION();
}
- if (iter && EXPECTED(EG(exception) == NULL)) {
- ZVAL_OBJ(&iterator, &iter->std);
- array_ptr = array_ref = &iterator;
+ 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 {
- if (IS_VAR == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
- if (free_op1) {zval_ptr_dtor_nogc(free_op1);};
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
+ }
+ } else if ((fe_ht = HASH_OF(array_ptr)) != NULL) {
+ if (IS_VAR != IS_TMP_VAR) {
+ if (Z_REFCOUNTED_P(array_ptr)) {
+ Z_ADDREF_P(array_ptr);
}
+ }
+ ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ptr);
+ Z_FE_POS_P(EX_VAR(opline->result.var)) = 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));
+ zval_ptr_dtor_nogc(free_op1);
+ ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+ }
+}
+
+static int ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ USE_OPLINE
+ zend_free_op free_op1;
+ zval *array_ptr, *array_ref;
+ HashTable *fe_ht;
+
+ SAVE_OPLINE();
+
+ if (IS_VAR == IS_VAR || IS_VAR == IS_CV) {
+ array_ref = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1);
+ ZVAL_MAKE_REF(array_ref);
+ array_ptr = Z_REFVAL_P(array_ref);
+ if (Z_TYPE_P(array_ptr) == IS_ARRAY) {
+ SEPARATE_ARRAY(array_ptr);
+ }
+ } else {
+ 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 (free_op1) {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();
}
- }
-
- ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref);
- if (iter) {
iter->index = 0;
if (iter->funcs->rewind) {
iter->funcs->rewind(iter);
if (UNEXPECTED(EG(exception) != NULL)) {
- zval_ptr_dtor(array_ref);
- if (IS_VAR == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
- if (free_op1) {zval_ptr_dtor_nogc(free_op1);};
- }
+ if (free_op1) {zval_ptr_dtor_nogc(free_op1);};
+ OBJ_RELEASE(&iter->std);
HANDLE_EXCEPTION();
}
}
+
is_empty = iter->funcs->valid(iter) != SUCCESS;
+
if (UNEXPECTED(EG(exception) != NULL)) {
- zval_ptr_dtor(array_ref);
- if (IS_VAR == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
- if (free_op1) {zval_ptr_dtor_nogc(free_op1);};
- }
+ if (free_op1) {zval_ptr_dtor_nogc(free_op1);};
+ OBJ_RELEASE(&iter->std);
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_POS_P(EX_VAR(opline->result.var)) = INVALID_IDX;
+ ZVAL_PTR(EX_VAR((opline+2)->op1.var), NULL);
+
+ if (free_op1) {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) {
- HashPointer *ptr = (HashPointer*)EX_VAR((opline+2)->op1.var);
HashPosition pos = 0;
Bucket *p;
+ if (IS_VAR != IS_TMP_VAR) {
+ if (Z_REFCOUNTED_P(array_ref)) {
+ Z_ADDREF_P(array_ref);
+ }
+ }
+ ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref);
while (1) {
if (pos >= fe_ht->nNumUsed) {
- is_empty = 1;
- if (IS_VAR == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
- if (free_op1) {zval_ptr_dtor_nogc(free_op1);};
- }
+ if (free_op1) {zval_ptr_dtor_nogc(free_op1);};
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)) {
- pos++;
- continue;
- }
- if (!ce ||
- !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)) &&
+ (Z_TYPE_P(array_ptr) != IS_OBJECT ||
+ !p->key ||
+ zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
break;
}
pos++;
}
- fe_ht->nInternalPointer = pos;
- ptr->pos = pos;
- ptr->ht = fe_ht;
- ptr->h = fe_ht->arData[pos].h;
- ptr->key = fe_ht->arData[pos].key;
- is_empty = 0;
- } else {
- zend_error(E_WARNING, "Invalid argument supplied for foreach()");
- is_empty = 1;
- }
+ Z_FE_POS_P(EX_VAR(opline->result.var)) = fe_ht->nInternalPointer = pos;
+ ZVAL_PTR(EX_VAR((opline+2)->op1.var), fe_ht);
- if (IS_VAR == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
if (free_op1) {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));
+ if (free_op1) {zval_ptr_dtor_nogc(free_op1);};
+ ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
}
}
-static int ZEND_FASTCALL ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+static int ZEND_FASTCALL ZEND_FE_FETCH_R_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
- zval *array, *array_ref;
+ zval *array;
zval *value;
HashTable *fe_ht;
- HashPointer *ptr;
HashPosition pos;
Bucket *p;
- array = array_ref = EX_VAR(opline->op1.var);
- if (Z_ISREF_P(array)) {
- array = Z_REFVAL_P(array);
- // TODO: referenced value might be changed to different array ???
- if (Z_IMMUTABLE_P(array)) {
- zval_copy_ctor_func(array);
+ array = EX_VAR(opline->op1.var);
+ SAVE_OPLINE();
+ if (EXPECTED(Z_TYPE_P(array) == IS_ARRAY)) {
+ fe_ht = Z_ARRVAL_P(array);
+ pos = Z_FE_POS_P(EX_VAR(opline->op1.var));
+ while (1) {
+ if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
+ /* reached end of iteration */
+ ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+ }
+ p = fe_ht->arData + pos;
+ value = &p->val;
+ if (Z_TYPE_P(value) == IS_UNDEF) {
+ pos++;
+ continue;
+ } else if (Z_TYPE_P(value) == IS_INDIRECT) {
+ value = Z_INDIRECT_P(value);
+ if (Z_TYPE_P(value) == IS_UNDEF) {
+ pos++;
+ continue;
+ }
+ }
+ break;
+ }
+ if (opline->extended_value) {
+ if (!p->key) {
+ ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
+ } else {
+ ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
+ }
+ }
+ ZVAL_COPY(EX_VAR(opline->result.var), value);
+ Z_FE_POS_P(EX_VAR(opline->op1.var)) = pos + 1;
+ ZEND_VM_INC_OPCODE();
+ ZEND_VM_NEXT_OPCODE();
+ } else if (EXPECTED(Z_TYPE_P(array) == IS_OBJECT)) {
+ zend_object_iterator *iter;
+
+ if ((iter = zend_iterator_unwrap(array)) == NULL) {
+ /* plain object */
+ zend_object *zobj = Z_OBJ_P(array);
+
+ fe_ht = Z_OBJPROP_P(array);
+ pos = Z_FE_POS_P(EX_VAR(opline->op1.var));
+ while (1) {
+ if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
+ /* reached end of iteration */
+ ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+ }
+
+ p = fe_ht->arData + pos;
+ value = &p->val;
+ if (Z_TYPE_P(value) == IS_UNDEF) {
+ pos++;
+ continue;
+ } else if (Z_TYPE_P(value) == IS_INDIRECT) {
+ value = Z_INDIRECT_P(value);
+ if (Z_TYPE_P(value) == IS_UNDEF) {
+ pos++;
+ continue;
+ }
+ }
+ if (!p->key ||
+ zend_check_property_access(Z_OBJ_P(array), p->key) == SUCCESS) {
+ break;
+ }
+ pos++;
+ }
+ if (opline->extended_value) {
+ if (UNEXPECTED(!p->key)) {
+ ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
+ } else if (p->key->val[0]) {
+ ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
+ } else {
+ const char *class_name, *prop_name;
+ size_t prop_name_len;
+ zend_unmangle_property_name_ex(
+ p->key, &class_name, &prop_name, &prop_name_len);
+ ZVAL_STRINGL(EX_VAR((opline+1)->result.var), prop_name, prop_name_len);
+ }
+ }
+ ZVAL_COPY(EX_VAR(opline->result.var), value);
+ Z_FE_POS_P(EX_VAR(opline->op1.var)) = pos + 1;
+ ZEND_VM_INC_OPCODE();
+ ZEND_VM_NEXT_OPCODE();
+ } else {
+ /* !iter happens from exception */
+ if (iter && ++iter->index > 0) {
+ /* This could cause an endless loop if index becomes zero again.
+ * In case that ever happens we need an additional flag. */
+ iter->funcs->move_forward(iter);
+ if (UNEXPECTED(EG(exception) != NULL)) {
+ zval_ptr_dtor(array);
+ HANDLE_EXCEPTION();
+ }
+ }
+ /* If index is zero we come from FE_RESET and checked valid() already. */
+ if (!iter || (iter->index > 0 && iter->funcs->valid(iter) == FAILURE)) {
+ /* reached end of iteration */
+ if (UNEXPECTED(EG(exception) != NULL)) {
+ zval_ptr_dtor(array);
+ HANDLE_EXCEPTION();
+ }
+ ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+ }
+ value = iter->funcs->get_current_data(iter);
+ if (UNEXPECTED(EG(exception) != NULL)) {
+ zval_ptr_dtor(array);
+ HANDLE_EXCEPTION();
+ }
+ if (!value) {
+ /* failure in get_current_data */
+ ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+ }
+ ZVAL_COPY(EX_VAR(opline->result.var), value);
+ if (opline->extended_value) {
+ if (iter->funcs->get_current_key) {
+ iter->funcs->get_current_key(iter, EX_VAR((opline+1)->result.var));
+ if (UNEXPECTED(EG(exception) != NULL)) {
+ zval_ptr_dtor(array);
+ HANDLE_EXCEPTION();
+ }
+ } else {
+ ZVAL_LONG(EX_VAR((opline+1)->result.var), iter->index);
+ }
+ }
+ ZEND_VM_INC_OPCODE();
+ ZEND_VM_NEXT_OPCODE();
}
+ } else {
+ zend_error(E_WARNING, "Invalid argument supplied for foreach()");
+ ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
}
+}
+static int ZEND_FASTCALL ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ USE_OPLINE
+
+ zval *array;
+ zval *value;
+ HashTable *fe_ht;
+ HashPosition pos;
+ Bucket *p;
+
+ array = EX_VAR(opline->op1.var);
SAVE_OPLINE();
+ ZVAL_DEREF(array);
if (EXPECTED(Z_TYPE_P(array) == IS_ARRAY)) {
fe_ht = Z_ARRVAL_P(array);
- ptr = (HashPointer*)EX_VAR((opline+1)->op1.var);
- pos = ptr->pos;
+ pos = Z_FE_POS_P(EX_VAR(opline->op1.var));
if (UNEXPECTED(pos == INVALID_IDX)) {
/* reached end of iteration */
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
- } else if (UNEXPECTED(ptr->ht != fe_ht)) {
- ptr->ht = fe_ht;
- pos = 0;
- } else if (UNEXPECTED(fe_ht->nInternalPointer != ptr->pos)) {
- if (fe_ht->u.flags & HASH_FLAG_PACKED) {
- pos = ptr->h;
- } else {
- pos = fe_ht->arHash[ptr->h & fe_ht->nTableMask];
- while (1) {
- if (pos == INVALID_IDX) {
- pos = fe_ht->nInternalPointer;
- break;
- } else if (fe_ht->arData[pos].h == ptr->h && fe_ht->arData[pos].key == ptr->key) {
- break;
- }
- pos = Z_NEXT(fe_ht->arData[pos].val);
- }
+ } else {
+ if (Z_PTR_P(EX_VAR((opline+1)->op1.var)) != fe_ht) {
+ pos = fe_ht->nInternalPointer;
}
+ SEPARATE_ARRAY(array);
+ fe_ht = Z_ARRVAL_P(array);
+ Z_PTR_P(EX_VAR((opline+1)->op1.var)) = fe_ht;
}
+//??? if (pos != fe_ht->nInternalPointer) {
+//??? //...
+//??? }
while (1) {
if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
/* reached end of iteration */
+ fe_ht->nInternalPointer = INVALID_IDX;
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
}
p = fe_ht->arData + pos;
value = &p->val;
- if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
+ if (Z_TYPE_P(value) == IS_UNDEF) {
pos++;
continue;
- } else if (UNEXPECTED(Z_TYPE_P(value) == IS_INDIRECT)) {
+ } else if (Z_TYPE_P(value) == IS_INDIRECT) {
value = Z_INDIRECT_P(value);
- if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
+ if (Z_TYPE_P(value) == IS_UNDEF) {
pos++;
continue;
}
}
- if (opline->extended_value & ZEND_FE_FETCH_BYREF) {
- ZVAL_MAKE_REF(value);
- Z_ADDREF_P(value);
- ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
+ break;
+ }
+ if (opline->extended_value) {
+ if (!p->key) {
+ ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
} else {
- ZVAL_COPY(EX_VAR(opline->result.var), value);
+ ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
}
- if (opline->extended_value & ZEND_FE_FETCH_WITH_KEY) {
- if (!p->key) {
- ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
- } else {
- ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
- }
- }
- break;
}
- do {
+ ZVAL_MAKE_REF(value);
+ Z_ADDREF_P(value);
+ ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
+ while (1) {
pos++;
if (pos >= fe_ht->nNumUsed) {
- fe_ht->nInternalPointer = ptr->pos = INVALID_IDX;
- ZEND_VM_INC_OPCODE();
- ZEND_VM_NEXT_OPCODE();
+ pos = INVALID_IDX;
+ break;
}
p = fe_ht->arData + pos;
- } while (Z_TYPE(p->val) == IS_UNDEF ||
- (Z_TYPE(p->val) == IS_INDIRECT &&
- Z_TYPE_P(Z_INDIRECT(p->val)) == IS_UNDEF));
- fe_ht->nInternalPointer = ptr->pos = pos;
- ptr->h = fe_ht->arData[pos].h;
- ptr->key = fe_ht->arData[pos].key;
+ if (Z_TYPE(p->val) != IS_UNDEF &&
+ (Z_TYPE(p->val) != IS_INDIRECT ||
+ Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) {
+ break;
+ }
+ }
+ Z_FE_POS_P(EX_VAR(opline->op1.var)) = fe_ht->nInternalPointer = pos;
ZEND_VM_INC_OPCODE();
ZEND_VM_NEXT_OPCODE();
} else if (EXPECTED(Z_TYPE_P(array) == IS_OBJECT)) {
@@ -12072,93 +12153,77 @@ static int ZEND_FASTCALL ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
zend_object *zobj = Z_OBJ_P(array);
fe_ht = Z_OBJPROP_P(array);
- ptr = (HashPointer*)EX_VAR((opline+1)->op1.var);
- pos = ptr->pos;
- if (pos == INVALID_IDX) {
+ pos = Z_FE_POS_P(EX_VAR(opline->op1.var));
+ if (UNEXPECTED(pos == INVALID_IDX)) {
/* reached end of iteration */
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
- } else if (UNEXPECTED(ptr->ht != fe_ht)) {
- ptr->ht = fe_ht;
- pos = 0;
- } else if (UNEXPECTED(fe_ht->nInternalPointer != ptr->pos)) {
- if (fe_ht->u.flags & HASH_FLAG_PACKED) {
- pos = ptr->h;
- } else {
- pos = fe_ht->arHash[ptr->h & fe_ht->nTableMask];
- while (1) {
- if (pos == INVALID_IDX) {
- pos = fe_ht->nInternalPointer;
- break;
- } else if (fe_ht->arData[pos].h == ptr->h && fe_ht->arData[pos].key == ptr->key) {
- break;
- }
- pos = Z_NEXT(fe_ht->arData[pos].val);
- }
+ } else {
+ if (Z_PTR_P(EX_VAR((opline+1)->op1.var)) != fe_ht) {
+ pos = fe_ht->nInternalPointer;
}
+ Z_PTR_P(EX_VAR((opline+1)->op1.var)) = fe_ht;
}
+//??? if (pos != fe_ht->nInternalPointer) {
+//???
+//??? }
while (1) {
if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
/* reached end of iteration */
+ fe_ht->nInternalPointer = INVALID_IDX;
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
}
p = fe_ht->arData + pos;
value = &p->val;
- if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
+ if (Z_TYPE_P(value) == IS_UNDEF) {
pos++;
continue;
- } else if (UNEXPECTED(Z_TYPE_P(value) == IS_INDIRECT)) {
+ } else if (Z_TYPE_P(value) == IS_INDIRECT) {
value = Z_INDIRECT_P(value);
- if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
+ if (Z_TYPE_P(value) == IS_UNDEF) {
pos++;
continue;
}
}
-
- if (UNEXPECTED(!p->key)) {
- if (opline->extended_value & ZEND_FE_FETCH_WITH_KEY) {
- ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
- }
- break;
- } else if (zend_check_property_access(zobj, p->key) == SUCCESS) {
- if (opline->extended_value & ZEND_FE_FETCH_WITH_KEY) {
- if (p->key->val[0]) {
- ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
- } else {
- const char *class_name, *prop_name;
- size_t prop_name_len;
- zend_unmangle_property_name_ex(
- p->key, &class_name, &prop_name, &prop_name_len);
- ZVAL_STRINGL(EX_VAR((opline+1)->result.var), prop_name, prop_name_len);
- }
- }
+ if (!p->key ||
+ zend_check_property_access(Z_OBJ_P(array), p->key) == SUCCESS) {
break;
}
pos++;
}
- if (opline->extended_value & ZEND_FE_FETCH_BYREF) {
- ZVAL_MAKE_REF(value);
- Z_ADDREF_P(value);
- ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
- } else {
- ZVAL_COPY(EX_VAR(opline->result.var), value);
+ if (opline->extended_value) {
+ if (UNEXPECTED(!p->key)) {
+ ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
+ } else if (p->key->val[0]) {
+ ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
+ } else {
+ const char *class_name, *prop_name;
+ size_t prop_name_len;
+ zend_unmangle_property_name_ex(
+ p->key, &class_name, &prop_name, &prop_name_len);
+ ZVAL_STRINGL(EX_VAR((opline+1)->result.var), prop_name, prop_name_len);
+ }
}
- do {
+ ZVAL_MAKE_REF(value);
+ Z_ADDREF_P(value);
+ ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
+ while (1) {
pos++;
if (pos >= fe_ht->nNumUsed) {
- fe_ht->nInternalPointer = ptr->pos = INVALID_IDX;
- ZEND_VM_INC_OPCODE();
- ZEND_VM_NEXT_OPCODE();
+ pos = INVALID_IDX;
+ break;
}
p = fe_ht->arData + pos;
- } while (Z_TYPE(p->val) == IS_UNDEF ||
- (Z_TYPE(p->val) == IS_INDIRECT &&
- Z_TYPE_P(Z_INDIRECT(p->val)) == IS_UNDEF) ||
- (EXPECTED(p->key != NULL) &&
- zend_check_property_access(zobj, p->key) == FAILURE));
- fe_ht->nInternalPointer = ptr->pos = pos;
- ptr->h = fe_ht->arData[pos].h;
- ptr->key = fe_ht->arData[pos].key;
+ 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;
+ }
+ }
+ Z_FE_POS_P(EX_VAR(opline->op1.var)) = fe_ht->nInternalPointer = pos;
ZEND_VM_INC_OPCODE();
ZEND_VM_NEXT_OPCODE();
} else {
@@ -12168,7 +12233,7 @@ static int ZEND_FASTCALL ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
* In case that ever happens we need an additional flag. */
iter->funcs->move_forward(iter);
if (UNEXPECTED(EG(exception) != NULL)) {
- zval_ptr_dtor(array_ref);
+ zval_ptr_dtor(array);
HANDLE_EXCEPTION();
}
}
@@ -12176,32 +12241,28 @@ static int ZEND_FASTCALL ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
if (!iter || (iter->index > 0 && iter->funcs->valid(iter) == FAILURE)) {
/* reached end of iteration */
if (UNEXPECTED(EG(exception) != NULL)) {
- zval_ptr_dtor(array_ref);
+ zval_ptr_dtor(array);
HANDLE_EXCEPTION();
}
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
}
value = iter->funcs->get_current_data(iter);
if (UNEXPECTED(EG(exception) != NULL)) {
- zval_ptr_dtor(array_ref);
+ zval_ptr_dtor(array);
HANDLE_EXCEPTION();
}
if (!value) {
/* failure in get_current_data */
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
}
- if (opline->extended_value & ZEND_FE_FETCH_BYREF) {
- ZVAL_MAKE_REF(value);
- Z_ADDREF_P(value);
- ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
- } else {
- ZVAL_COPY(EX_VAR(opline->result.var), value);
- }
- if (opline->extended_value & ZEND_FE_FETCH_WITH_KEY) {
+ ZVAL_MAKE_REF(value);
+ Z_ADDREF_P(value);
+ ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
+ if (opline->extended_value) {
if (iter->funcs->get_current_key) {
iter->funcs->get_current_key(iter, EX_VAR((opline+1)->result.var));
if (UNEXPECTED(EG(exception) != NULL)) {
- zval_ptr_dtor(array_ref);
+ zval_ptr_dtor(array);
HANDLE_EXCEPTION();
}
} else {
@@ -24064,194 +24125,178 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CV_HANDLER(ZEND_OPCODE_HANDL
ZEND_VM_NEXT_OPCODE();
}
-static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+static int ZEND_FASTCALL ZEND_FE_RESET_R_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
- zval *array_ptr, *array_ref, iterator, tmp;
+ zval *array_ptr;
HashTable *fe_ht;
- zend_object_iterator *iter = NULL;
- zend_class_entry *ce = NULL;
- zend_bool is_empty = 0;
SAVE_OPLINE();
- if ((IS_CV == IS_CV || IS_CV == IS_VAR) &&
- (opline->extended_value & ZEND_FE_FETCH_BYREF)) {
- array_ptr = array_ref = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var);
- ZVAL_DEREF(array_ptr);
- if (Z_TYPE_P(array_ptr) == IS_ARRAY) {
- SEPARATE_ARRAY(array_ptr);
- if (!Z_ISREF_P(array_ref)) {
- ZVAL_NEW_REF(array_ref, array_ref);
- array_ptr = Z_REFVAL_P(array_ref);
- }
- if (Z_REFCOUNTED_P(array_ref)) Z_ADDREF_P(array_ref);
- } else if (Z_TYPE_P(array_ptr) == IS_OBJECT) {
- ce = Z_OBJCE_P(array_ptr);
- if (ce->get_iterator == NULL) {
- Z_ADDREF_P(array_ptr);
+ array_ptr = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var);
+ ZVAL_DEREF(array_ptr);
+ 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 (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);
}
- array_ref = array_ptr;
- } else {
- if (Z_REFCOUNTED_P(array_ref)) Z_ADDREF_P(array_ref);
- }
- } else {
- array_ptr = array_ref = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var);
- if (IS_CV & (IS_VAR|IS_CV)) {
- ZVAL_DEREF(array_ptr);
+ zend_throw_exception_internal(NULL);
+ HANDLE_EXCEPTION();
}
- if (IS_CV == IS_TMP_VAR) {
- ZVAL_COPY_VALUE(&tmp, array_ptr);
- if (Z_OPT_IMMUTABLE_P(&tmp)) {
- zval_copy_ctor_func(&tmp);
- }
- array_ref = array_ptr = &tmp;
- if (Z_TYPE_P(array_ptr) == IS_OBJECT) {
- ce = Z_OBJCE_P(array_ptr);
- if (ce && ce->get_iterator) {
- Z_DELREF_P(array_ref);
- }
- }
- } else if (Z_TYPE_P(array_ptr) == IS_OBJECT) {
- ce = Z_OBJCE_P(array_ptr);
- if (!ce->get_iterator) {
- if (IS_CV == IS_CV) {
- Z_ADDREF_P(array_ref);
- }
+
+ iter->index = 0;
+ if (iter->funcs->rewind) {
+ iter->funcs->rewind(iter);
+ if (UNEXPECTED(EG(exception) != NULL)) {
+
+ OBJ_RELEASE(&iter->std);
+ HANDLE_EXCEPTION();
}
- } else if (Z_IMMUTABLE_P(array_ref)) {
- if (IS_CV == IS_CV) {
- zval_copy_ctor_func(array_ref);
- Z_ADDREF_P(array_ref);
- } else {
- ZVAL_COPY_VALUE(&tmp, array_ref);
- zval_copy_ctor_func(&tmp);
- array_ptr = array_ref = &tmp;
- }
- } else if (Z_REFCOUNTED_P(array_ref)) {
- if (IS_CV == IS_CONST ||
- (IS_CV == IS_CV &&
- !Z_ISREF_P(array_ref) &&
- Z_REFCOUNT_P(array_ref) > 1) ||
- (IS_CV == IS_VAR &&
- !Z_ISREF_P(array_ref) &&
- Z_REFCOUNT_P(array_ref) > 2)) {
- if (IS_CV == IS_VAR) {
- Z_DELREF_P(array_ref);
- }
- ZVAL_DUP(&tmp, array_ref);
- array_ptr = array_ref = &tmp;
- } else if (IS_CV == IS_CV || IS_CV == IS_VAR) {
- if (Z_ISREF_P(array_ref) && Z_REFCOUNT_P(array_ref) == 1) {
- ZVAL_UNREF(array_ref);
- array_ptr = array_ref;
- }
- if (Z_IMMUTABLE_P(array_ptr)) {
- zval_copy_ctor_func(array_ptr);
- } else if (Z_ISREF_P(array_ref) &&
- Z_COPYABLE_P(array_ptr) &&
- Z_REFCOUNT_P(array_ptr) > 1) {
- Z_DELREF_P(array_ptr);
- zval_copy_ctor_func(array_ptr);
- }
- if (IS_CV == IS_CV) {
- Z_ADDREF_P(array_ref);
- }
+ }
+
+ is_empty = iter->funcs->valid(iter) != SUCCESS;
+
+ if (UNEXPECTED(EG(exception) != NULL)) {
+
+ OBJ_RELEASE(&iter->std);
+ HANDLE_EXCEPTION();
+ }
+ iter->index = -1; /* will be set to 0 before using next handler */
+
+ ZVAL_OBJ(EX_VAR(opline->result.var), &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) {
+ if (IS_CV != IS_TMP_VAR) {
+ if (Z_REFCOUNTED_P(array_ptr)) {
+ Z_ADDREF_P(array_ptr);
}
}
+ ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ptr);
+ Z_FE_POS_P(EX_VAR(opline->result.var)) = 0;
+
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
+ } else {
+ zend_error(E_WARNING, "Invalid argument supplied for foreach()");
+ ZVAL_UNDEF(EX_VAR(opline->result.var));
+
+ ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
}
+}
- if (ce && ce->get_iterator) {
- iter = ce->get_iterator(ce, array_ptr, opline->extended_value & ZEND_FE_FETCH_BYREF);
+static int ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ USE_OPLINE
- if (IS_CV == IS_VAR && !(opline->extended_value & ZEND_FE_FETCH_BYREF)) {
+ zval *array_ptr, *array_ref;
+ HashTable *fe_ht;
+ SAVE_OPLINE();
+
+ if (IS_CV == IS_VAR || IS_CV == IS_CV) {
+ array_ref = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var);
+ ZVAL_MAKE_REF(array_ref);
+ array_ptr = Z_REFVAL_P(array_ref);
+ if (Z_TYPE_P(array_ptr) == IS_ARRAY) {
+ SEPARATE_ARRAY(array_ptr);
}
- if (iter && EXPECTED(EG(exception) == NULL)) {
- ZVAL_OBJ(&iterator, &iter->std);
- array_ptr = array_ref = &iterator;
- } else {
- if (IS_CV == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
+ } else {
+ 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 (!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();
}
- }
- ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref);
-
- if (iter) {
iter->index = 0;
if (iter->funcs->rewind) {
iter->funcs->rewind(iter);
if (UNEXPECTED(EG(exception) != NULL)) {
- zval_ptr_dtor(array_ref);
- if (IS_CV == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
- }
+ OBJ_RELEASE(&iter->std);
HANDLE_EXCEPTION();
}
}
+
is_empty = iter->funcs->valid(iter) != SUCCESS;
+
if (UNEXPECTED(EG(exception) != NULL)) {
- zval_ptr_dtor(array_ref);
- if (IS_CV == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
- }
+ OBJ_RELEASE(&iter->std);
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_POS_P(EX_VAR(opline->result.var)) = INVALID_IDX;
+ ZVAL_PTR(EX_VAR((opline+2)->op1.var), NULL);
+
+ 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) {
- HashPointer *ptr = (HashPointer*)EX_VAR((opline+2)->op1.var);
HashPosition pos = 0;
Bucket *p;
+ if (IS_CV != IS_TMP_VAR) {
+ if (Z_REFCOUNTED_P(array_ref)) {
+ Z_ADDREF_P(array_ref);
+ }
+ }
+ ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref);
while (1) {
if (pos >= fe_ht->nNumUsed) {
- is_empty = 1;
- if (IS_CV == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
- }
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)) {
- pos++;
- continue;
- }
- if (!ce ||
- !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)) &&
+ (Z_TYPE_P(array_ptr) != IS_OBJECT ||
+ !p->key ||
+ zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
break;
}
pos++;
}
- fe_ht->nInternalPointer = pos;
- ptr->pos = pos;
- ptr->ht = fe_ht;
- ptr->h = fe_ht->arData[pos].h;
- ptr->key = fe_ht->arData[pos].key;
- is_empty = 0;
+ Z_FE_POS_P(EX_VAR(opline->result.var)) = fe_ht->nInternalPointer = pos;
+ ZVAL_PTR(EX_VAR((opline+2)->op1.var), fe_ht);
+
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
} else {
zend_error(E_WARNING, "Invalid argument supplied for foreach()");
- is_empty = 1;
- }
-
- if (IS_CV == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
+ ZVAL_UNDEF(EX_VAR(opline->result.var));
- }
- if (is_empty) {
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
- } else {
- CHECK_EXCEPTION();
- ZEND_VM_NEXT_OPCODE();
}
}
@@ -38295,31 +38340,31 @@ void zend_init_opcodes_handlers(void)
ZEND_UNSET_OBJ_SPEC_CV_TMPVAR_HANDLER,
ZEND_NULL_HANDLER,
ZEND_UNSET_OBJ_SPEC_CV_CV_HANDLER,
- ZEND_FE_RESET_SPEC_CONST_HANDLER,
- ZEND_FE_RESET_SPEC_CONST_HANDLER,
- ZEND_FE_RESET_SPEC_CONST_HANDLER,
- ZEND_FE_RESET_SPEC_CONST_HANDLER,
- ZEND_FE_RESET_SPEC_CONST_HANDLER,
- ZEND_FE_RESET_SPEC_TMP_HANDLER,
- ZEND_FE_RESET_SPEC_TMP_HANDLER,
- ZEND_FE_RESET_SPEC_TMP_HANDLER,
- ZEND_FE_RESET_SPEC_TMP_HANDLER,
- ZEND_FE_RESET_SPEC_TMP_HANDLER,
- ZEND_FE_RESET_SPEC_VAR_HANDLER,
- ZEND_FE_RESET_SPEC_VAR_HANDLER,
- ZEND_FE_RESET_SPEC_VAR_HANDLER,
- ZEND_FE_RESET_SPEC_VAR_HANDLER,
- ZEND_FE_RESET_SPEC_VAR_HANDLER,
+ ZEND_FE_RESET_R_SPEC_CONST_HANDLER,
+ ZEND_FE_RESET_R_SPEC_CONST_HANDLER,
+ ZEND_FE_RESET_R_SPEC_CONST_HANDLER,
+ ZEND_FE_RESET_R_SPEC_CONST_HANDLER,
+ ZEND_FE_RESET_R_SPEC_CONST_HANDLER,
+ ZEND_FE_RESET_R_SPEC_TMP_HANDLER,
+ ZEND_FE_RESET_R_SPEC_TMP_HANDLER,
+ ZEND_FE_RESET_R_SPEC_TMP_HANDLER,
+ ZEND_FE_RESET_R_SPEC_TMP_HANDLER,
+ ZEND_FE_RESET_R_SPEC_TMP_HANDLER,
+ ZEND_FE_RESET_R_SPEC_VAR_HANDLER,
+ ZEND_FE_RESET_R_SPEC_VAR_HANDLER,
+ ZEND_FE_RESET_R_SPEC_VAR_HANDLER,
+ ZEND_FE_RESET_R_SPEC_VAR_HANDLER,
+ ZEND_FE_RESET_R_SPEC_VAR_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
- ZEND_FE_RESET_SPEC_CV_HANDLER,
- ZEND_FE_RESET_SPEC_CV_HANDLER,
- ZEND_FE_RESET_SPEC_CV_HANDLER,
- ZEND_FE_RESET_SPEC_CV_HANDLER,
- ZEND_FE_RESET_SPEC_CV_HANDLER,
+ ZEND_FE_RESET_R_SPEC_CV_HANDLER,
+ ZEND_FE_RESET_R_SPEC_CV_HANDLER,
+ ZEND_FE_RESET_R_SPEC_CV_HANDLER,
+ ZEND_FE_RESET_R_SPEC_CV_HANDLER,
+ ZEND_FE_RESET_R_SPEC_CV_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
@@ -38330,11 +38375,11 @@ void zend_init_opcodes_handlers(void)
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
- ZEND_FE_FETCH_SPEC_VAR_HANDLER,
- ZEND_FE_FETCH_SPEC_VAR_HANDLER,
- ZEND_FE_FETCH_SPEC_VAR_HANDLER,
- ZEND_FE_FETCH_SPEC_VAR_HANDLER,
- ZEND_FE_FETCH_SPEC_VAR_HANDLER,
+ ZEND_FE_FETCH_R_SPEC_VAR_HANDLER,
+ ZEND_FE_FETCH_R_SPEC_VAR_HANDLER,
+ ZEND_FE_FETCH_R_SPEC_VAR_HANDLER,
+ ZEND_FE_FETCH_R_SPEC_VAR_HANDLER,
+ ZEND_FE_FETCH_R_SPEC_VAR_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
@@ -39495,11 +39540,31 @@ void zend_init_opcodes_handlers(void)
ZEND_NULL_HANDLER,
ZEND_VERIFY_RETURN_TYPE_SPEC_CV_UNUSED_HANDLER,
ZEND_NULL_HANDLER,
+ ZEND_FE_RESET_RW_SPEC_CONST_HANDLER,
+ ZEND_FE_RESET_RW_SPEC_CONST_HANDLER,
+ ZEND_FE_RESET_RW_SPEC_CONST_HANDLER,
+ ZEND_FE_RESET_RW_SPEC_CONST_HANDLER,
+ ZEND_FE_RESET_RW_SPEC_CONST_HANDLER,
+ ZEND_FE_RESET_RW_SPEC_TMP_HANDLER,
+ ZEND_FE_RESET_RW_SPEC_TMP_HANDLER,
+ ZEND_FE_RESET_RW_SPEC_TMP_HANDLER,
+ ZEND_FE_RESET_RW_SPEC_TMP_HANDLER,
+ ZEND_FE_RESET_RW_SPEC_TMP_HANDLER,
+ ZEND_FE_RESET_RW_SPEC_VAR_HANDLER,
+ ZEND_FE_RESET_RW_SPEC_VAR_HANDLER,
+ ZEND_FE_RESET_RW_SPEC_VAR_HANDLER,
+ ZEND_FE_RESET_RW_SPEC_VAR_HANDLER,
+ ZEND_FE_RESET_RW_SPEC_VAR_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
+ ZEND_FE_RESET_RW_SPEC_CV_HANDLER,
+ ZEND_FE_RESET_RW_SPEC_CV_HANDLER,
+ ZEND_FE_RESET_RW_SPEC_CV_HANDLER,
+ ZEND_FE_RESET_RW_SPEC_CV_HANDLER,
+ ZEND_FE_RESET_RW_SPEC_CV_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
@@ -39510,31 +39575,11 @@ void zend_init_opcodes_handlers(void)
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
+ ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER,
+ ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER,
+ ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER,
+ ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER,
+ ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c
index c3006e6036..295600c6fd 100644
--- a/Zend/zend_vm_opcodes.c
+++ b/Zend/zend_vm_opcodes.c
@@ -99,8 +99,8 @@ const char *zend_vm_opcodes_map[170] = {
"ZEND_UNSET_VAR",
"ZEND_UNSET_DIM",
"ZEND_UNSET_OBJ",
- "ZEND_FE_RESET",
- "ZEND_FE_FETCH",
+ "ZEND_FE_RESET_R",
+ "ZEND_FE_FETCH_R",
"ZEND_EXIT",
"ZEND_FETCH_R",
"ZEND_FETCH_DIM_R",
@@ -147,8 +147,8 @@ const char *zend_vm_opcodes_map[170] = {
"ZEND_DEFINED",
"ZEND_TYPE_CHECK",
"ZEND_VERIFY_RETURN_TYPE",
- NULL,
- NULL,
+ "ZEND_FE_RESET_RW",
+ "ZEND_FE_FETCH_RW",
NULL,
NULL,
NULL,
diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h
index f0fc7c7182..9cb1679e98 100644
--- a/Zend/zend_vm_opcodes.h
+++ b/Zend/zend_vm_opcodes.h
@@ -101,8 +101,8 @@ END_EXTERN_C()
#define ZEND_UNSET_VAR 74
#define ZEND_UNSET_DIM 75
#define ZEND_UNSET_OBJ 76
-#define ZEND_FE_RESET 77
-#define ZEND_FE_FETCH 78
+#define ZEND_FE_RESET_R 77
+#define ZEND_FE_FETCH_R 78
#define ZEND_EXIT 79
#define ZEND_FETCH_R 80
#define ZEND_FETCH_DIM_R 81
@@ -149,6 +149,8 @@ END_EXTERN_C()
#define ZEND_DEFINED 122
#define ZEND_TYPE_CHECK 123
#define ZEND_VERIFY_RETURN_TYPE 124
+#define ZEND_FE_RESET_RW 125
+#define ZEND_FE_FETCH_RW 126
#define ZEND_PRE_INC_OBJ 132
#define ZEND_PRE_DEC_OBJ 133
#define ZEND_POST_INC_OBJ 134
diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c
index 7948990f81..3df0faa0ef 100644
--- a/ext/opcache/Optimizer/block_pass.c
+++ b/ext/opcache/Optimizer/block_pass.c
@@ -166,14 +166,16 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimiz
case ZEND_JMPNZ:
case ZEND_JMPZ_EX:
case ZEND_JMPNZ_EX:
- case ZEND_FE_RESET:
+ case ZEND_FE_RESET_R:
+ case ZEND_FE_RESET_RW:
case ZEND_NEW:
case ZEND_JMP_SET:
case ZEND_COALESCE:
START_BLOCK_OP(ZEND_OP2(opline).opline_num);
START_BLOCK_OP(opno + 1);
break;
- case ZEND_FE_FETCH:
+ case ZEND_FE_FETCH_R:
+ case ZEND_FE_FETCH_RW:
START_BLOCK_OP(ZEND_OP2(opline).opline_num);
START_BLOCK_OP(opno + 2);
break;
@@ -293,11 +295,13 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimiz
case ZEND_JMPNZ:
case ZEND_JMPZ_EX:
case ZEND_JMPNZ_EX:
- case ZEND_FE_RESET:
+ case ZEND_FE_RESET_R:
+ case ZEND_FE_RESET_RW:
case ZEND_NEW:
case ZEND_JMP_SET:
case ZEND_COALESCE:
- case ZEND_FE_FETCH:
+ case ZEND_FE_FETCH_R:
+ case ZEND_FE_FETCH_RW:
cur_block->op2_to = &blocks[ZEND_OP2(opline).opline_num];
/* break missing intentionally */
default:
@@ -619,7 +623,7 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array,
ZEND_OP1_TYPE(VAR_SOURCE(opline->op1)) == IS_CONST &&
opline->opcode != ZEND_CASE && /* CASE _always_ expects variable */
opline->opcode != ZEND_FETCH_LIST &&
- opline->opcode != ZEND_FE_RESET &&
+ (opline->opcode != ZEND_FE_RESET_R || opline->opcode != ZEND_FE_RESET_RW) &&
opline->opcode != ZEND_FREE
) {
zend_op *src = VAR_SOURCE(opline->op1);
diff --git a/ext/opcache/Optimizer/nop_removal.c b/ext/opcache/Optimizer/nop_removal.c
index 0bb8cce17f..dccd010ae4 100644
--- a/ext/opcache/Optimizer/nop_removal.c
+++ b/ext/opcache/Optimizer/nop_removal.c
@@ -93,8 +93,10 @@ void zend_optimizer_nop_removal(zend_op_array *op_array)
case ZEND_JMPNZ:
case ZEND_JMPZ_EX:
case ZEND_JMPNZ_EX:
- case ZEND_FE_FETCH:
- case ZEND_FE_RESET:
+ case ZEND_FE_FETCH_R:
+ case ZEND_FE_FETCH_RW:
+ case ZEND_FE_RESET_R:
+ case ZEND_FE_RESET_RW:
case ZEND_NEW:
case ZEND_JMP_SET:
case ZEND_COALESCE:
diff --git a/ext/opcache/Optimizer/optimize_temp_vars_5.c b/ext/opcache/Optimizer/optimize_temp_vars_5.c
index 27ba6bad8e..ac5389ed2b 100644
--- a/ext/opcache/Optimizer/optimize_temp_vars_5.c
+++ b/ext/opcache/Optimizer/optimize_temp_vars_5.c
@@ -66,15 +66,12 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c
if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) {
start_of_T[VAR_NUM(ZEND_RESULT(opline).var) - offset] = opline;
}
- /* special puprose variable to keep HashPointer on VM stack */
+ /* special puprose variable to keep HashTable* on VM stack */
if (opline->opcode == ZEND_OP_DATA &&
- (opline-1)->opcode == ZEND_FE_FETCH &&
+ (opline-1)->opcode == ZEND_FE_FETCH_RW &&
+ (opline-2)->opcode == ZEND_FE_RESET_RW &&
opline->op1_type == IS_TMP_VAR) {
- start_of_T[VAR_NUM(ZEND_OP1(opline).var) - offset] = opline;
- if (sizeof(HashPointer) > sizeof(zval)) {
- /* Make shure 1 zval is enough for HashPointer (2 must be enough) */
- start_of_T[VAR_NUM(ZEND_OP1(opline).var) + 1 - offset] = opline;
- }
+ start_of_T[VAR_NUM(ZEND_OP1(opline).var) - offset] = opline - 2;
}
opline--;
}
@@ -88,25 +85,13 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c
while (opline >= end) {
if ((ZEND_OP1_TYPE(opline) & (IS_VAR | IS_TMP_VAR))) {
- /* special puprose variable to keep HashPointer on VM stack */
- if (opline->opcode == ZEND_OP_DATA &&
- (opline-1)->opcode == ZEND_FE_FETCH &&
- opline->op1_type == IS_TMP_VAR) {
- max++;
- ZEND_OP1(opline).var = NUM_VAR(max + offset);
- if (sizeof(HashPointer) > sizeof(zval)) {
- /* Make shure 1 zval is enough for HashPointer (2 must be enough) */
- max++;
- }
- } else {
- currT = VAR_NUM(ZEND_OP1(opline).var) - offset;
- if (!valid_T[currT]) {
- GET_AVAILABLE_T();
- map_T[currT] = i;
- valid_T[currT] = 1;
- }
- ZEND_OP1(opline).var = NUM_VAR(map_T[currT] + offset);
+ currT = VAR_NUM(ZEND_OP1(opline).var) - offset;
+ if (!valid_T[currT]) {
+ GET_AVAILABLE_T();
+ map_T[currT] = i;
+ valid_T[currT] = 1;
}
+ ZEND_OP1(opline).var = NUM_VAR(map_T[currT] + offset);
}
/* Skip OP_DATA */
diff --git a/ext/opcache/Optimizer/pass1_5.c b/ext/opcache/Optimizer/pass1_5.c
index 348fcb8efb..341e80501b 100644
--- a/ext/opcache/Optimizer/pass1_5.c
+++ b/ext/opcache/Optimizer/pass1_5.c
@@ -602,8 +602,10 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
case ZEND_JMPNZ:
case ZEND_JMPZ_EX:
case ZEND_JMPNZ_EX:
- case ZEND_FE_RESET:
- case ZEND_FE_FETCH:
+ case ZEND_FE_RESET_R:
+ case ZEND_FE_RESET_RW:
+ case ZEND_FE_FETCH_R:
+ case ZEND_FE_FETCH_RW:
case ZEND_NEW:
case ZEND_JMP_SET:
case ZEND_COALESCE:
diff --git a/ext/opcache/Optimizer/pass3.c b/ext/opcache/Optimizer/pass3.c
index c3a55b319f..3019b274e9 100644
--- a/ext/opcache/Optimizer/pass3.c
+++ b/ext/opcache/Optimizer/pass3.c
@@ -328,7 +328,8 @@ continue_jmp_ex_optimization:
op->opcode == ZEND_RETURN ||
op->opcode == ZEND_RETURN_BY_REF ||
op->opcode == ZEND_FAST_RET ||
- op->opcode == ZEND_FE_FETCH ||
+ op->opcode == ZEND_FE_FETCH_R ||
+ op->opcode == ZEND_FE_FETCH_RW ||
op->opcode == ZEND_EXIT) {
break;
}
@@ -363,7 +364,8 @@ continue_jmp_ex_optimization:
op->opcode == ZEND_RETURN ||
op->opcode == ZEND_RETURN_BY_REF ||
op->opcode == ZEND_FAST_RET ||
- op->opcode == ZEND_FE_FETCH ||
+ op->opcode == ZEND_FE_FETCH_R ||
+ op->opcode == ZEND_FE_FETCH_RW ||
op->opcode == ZEND_EXIT) {
break;
}
diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c
index 54063d0ed3..a8506fb078 100644
--- a/ext/opcache/Optimizer/zend_optimizer.c
+++ b/ext/opcache/Optimizer/zend_optimizer.c
@@ -450,8 +450,10 @@ static void zend_accel_optimize(zend_op_array *op_array,
case ZEND_JMP_SET:
case ZEND_COALESCE:
case ZEND_NEW:
- case ZEND_FE_RESET:
- case ZEND_FE_FETCH:
+ case ZEND_FE_RESET_R:
+ case ZEND_FE_RESET_RW:
+ case ZEND_FE_FETCH_R:
+ case ZEND_FE_FETCH_RW:
ZEND_PASS_TWO_UNDO_JMP_TARGET(op_array, opline, ZEND_OP2(opline));
break;
}
@@ -488,8 +490,10 @@ static void zend_accel_optimize(zend_op_array *op_array,
case ZEND_JMP_SET:
case ZEND_COALESCE:
case ZEND_NEW:
- case ZEND_FE_RESET:
- case ZEND_FE_FETCH:
+ case ZEND_FE_RESET_R:
+ case ZEND_FE_RESET_RW:
+ case ZEND_FE_FETCH_R:
+ case ZEND_FE_FETCH_RW:
ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, ZEND_OP2(opline));
break;
}
diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c
index 3d63f96e34..5b32baa64b 100644
--- a/ext/opcache/zend_persist.c
+++ b/ext/opcache/zend_persist.c
@@ -378,8 +378,10 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc
case ZEND_JMP_SET:
case ZEND_COALESCE:
case ZEND_NEW:
- case ZEND_FE_RESET:
- case ZEND_FE_FETCH:
+ case ZEND_FE_RESET_R:
+ case ZEND_FE_RESET_RW:
+ case ZEND_FE_FETCH_R:
+ case ZEND_FE_FETCH_RW:
ZEND_OP2(opline).jmp_addr = &new_opcodes[ZEND_OP2(opline).jmp_addr - op_array->opcodes];
break;
}
diff --git a/tests/lang/bug23624.phpt b/tests/lang/bug23624.phpt
index 4ddb82e8c6..f8778fffe3 100644
--- a/tests/lang/bug23624.phpt
+++ b/tests/lang/bug23624.phpt
@@ -9,4 +9,4 @@ Bug #23624 (foreach leaves current array key as null)
?>
--EXPECT--
string(3) "one"
-bool(false)
+string(3) "one"
diff --git a/tests/lang/foreachLoop.001.phpt b/tests/lang/foreachLoop.001.phpt
index b24f14e81d..c35b9b44e5 100644
--- a/tests/lang/foreachLoop.001.phpt
+++ b/tests/lang/foreachLoop.001.phpt
@@ -60,5 +60,5 @@ string(1) "f"
int(2)
string(1) "f"
-bool(false)
+string(1) "a"
bool(false)
diff --git a/tests/lang/foreachLoop.009.phpt b/tests/lang/foreachLoop.009.phpt
index 4586a35a10..df51fd6be4 100644
--- a/tests/lang/foreachLoop.009.phpt
+++ b/tests/lang/foreachLoop.009.phpt
@@ -55,6 +55,7 @@ foreach ($refedArray as $k=>&$v4) {
Remove elements from a referenced array during loop
key: 0; value: original.0
key: 1; value: original.1
+key: 2; value: original.2
Remove elements from a referenced array during loop, using &$value
key: 0; value: original.0
@@ -64,11 +65,6 @@ Add elements to a referenced array during loop
key: 0; value: original.0
key: 1; value: original.1
key: 2; value: original.2
-key: 3; value: new.0
-key: 4; value: new.1
-key: 5; value: new.2
-key: 6; value: new.3
-Loop detected, as expected.
Add elements to a referenced array during loop, using &$value
key: 0; value: original.0
diff --git a/tests/lang/foreachLoop.011.phpt b/tests/lang/foreachLoop.011.phpt
index 671cfaf354..8527a8833e 100644
--- a/tests/lang/foreachLoop.011.phpt
+++ b/tests/lang/foreachLoop.011.phpt
@@ -25,10 +25,9 @@ foreach ($a as $v) {
Change from array to non iterable:
int(1)
-
-Warning: Invalid argument supplied for foreach() in %s on line 5
+int(2)
+int(3)
Change from object to non iterable:
int(1)
-
-Warning: Invalid argument supplied for foreach() in %s on line 15
+int(2)
diff --git a/tests/lang/foreachLoop.014.phpt b/tests/lang/foreachLoop.014.phpt
index d32ea635fd..9b179ab22a 100644
--- a/tests/lang/foreachLoop.014.phpt
+++ b/tests/lang/foreachLoop.014.phpt
@@ -1,7 +1,5 @@
--TEST--
Directly modifying a REFERENCED array when foreach'ing over it.
---XFAIL--
-Needs major foreach changes to get sane behavior
--FILE--
<?php
@@ -96,7 +94,7 @@ array(2) {
}
--> Do loop:
iteration 0: $k=0; $v=v.0
- iteration 1: $k=0; $v=v.0
+ iteration 1: $k=1; $v=v.1
--> State of array after loop:
array(0) {
}
@@ -114,10 +112,9 @@ array(3) {
--> Do loop:
iteration 0: $k=0; $v=v.0
iteration 1: $k=1; $v=v.1
+ iteration 2: $k=2; $v=v.2
--> State of array after loop:
-array(1) {
- [0]=>
- string(3) "v.0"
+array(0) {
}
---( Array with 4 element(s): )---
@@ -135,8 +132,8 @@ array(4) {
--> Do loop:
iteration 0: $k=0; $v=v.0
iteration 1: $k=1; $v=v.1
- iteration 2: $k=0; $v=v.0
- iteration 3: $k=0; $v=v.0
+ iteration 2: $k=2; $v=v.2
+ iteration 3: $k=3; $v=v.3
--> State of array after loop:
array(0) {
}
@@ -166,7 +163,7 @@ array(2) {
}
--> Do loop:
iteration 0: $k=0; $v=v.0
- iteration 1: $k=0; $v=v.1
+ iteration 1: $k=1; $v=v.1
--> State of array after loop:
array(0) {
}
@@ -183,8 +180,8 @@ array(3) {
}
--> Do loop:
iteration 0: $k=0; $v=v.0
- iteration 1: $k=0; $v=v.1
- iteration 2: $k=0; $v=v.2
+ iteration 1: $k=1; $v=v.1
+ iteration 2: $k=2; $v=v.2
--> State of array after loop:
array(0) {
}
@@ -203,9 +200,9 @@ array(4) {
}
--> Do loop:
iteration 0: $k=0; $v=v.0
- iteration 1: $k=0; $v=v.1
- iteration 2: $k=0; $v=v.2
- iteration 3: $k=0; $v=v.3
+ iteration 1: $k=1; $v=v.1
+ iteration 2: $k=2; $v=v.2
+ iteration 3: $k=3; $v=v.3
--> State of array after loop:
array(0) {
}
@@ -309,13 +306,8 @@ array(2) {
--> Do loop:
iteration 0: $k=0; $v=v.0
iteration 1: $k=1; $v=v.1
- iteration 2: $k=2; $v=new.0
- iteration 3: $k=3; $v=new.1
- iteration 4: $k=4; $v=new.2
- iteration 5: $k=5; $v=new.3
- ** Stuck in a loop! **
--> State of array after loop:
-array(8) {
+array(4) {
[0]=>
string(3) "v.0"
[1]=>
@@ -324,14 +316,6 @@ array(8) {
string(5) "new.0"
[3]=>
string(5) "new.1"
- [4]=>
- string(5) "new.2"
- [5]=>
- string(5) "new.3"
- [6]=>
- string(5) "new.4"
- [7]=>
- string(5) "new.5"
}
---( Array with 3 element(s): )---
@@ -348,12 +332,8 @@ array(3) {
iteration 0: $k=0; $v=v.0
iteration 1: $k=1; $v=v.1
iteration 2: $k=2; $v=v.2
- iteration 3: $k=3; $v=new.0
- iteration 4: $k=4; $v=new.1
- iteration 5: $k=5; $v=new.2
- ** Stuck in a loop! **
--> State of array after loop:
-array(9) {
+array(6) {
[0]=>
string(3) "v.0"
[1]=>
@@ -366,12 +346,6 @@ array(9) {
string(5) "new.1"
[5]=>
string(5) "new.2"
- [6]=>
- string(5) "new.3"
- [7]=>
- string(5) "new.4"
- [8]=>
- string(5) "new.5"
}
---( Array with 4 element(s): )---
@@ -391,11 +365,8 @@ array(4) {
iteration 1: $k=1; $v=v.1
iteration 2: $k=2; $v=v.2
iteration 3: $k=3; $v=v.3
- iteration 4: $k=4; $v=new.0
- iteration 5: $k=5; $v=new.1
- ** Stuck in a loop! **
--> State of array after loop:
-array(10) {
+array(8) {
[0]=>
string(3) "v.0"
[1]=>
@@ -412,10 +383,6 @@ array(10) {
string(5) "new.2"
[7]=>
string(5) "new.3"
- [8]=>
- string(5) "new.4"
- [9]=>
- string(5) "new.5"
}
@@ -447,29 +414,16 @@ array(2) {
}
--> Do loop:
iteration 0: $k=0; $v=v.0
- iteration 1: $k=0; $v=new.0
- iteration 2: $k=0; $v=new.1
- iteration 3: $k=0; $v=new.2
- iteration 4: $k=0; $v=new.3
- iteration 5: $k=0; $v=new.4
- ** Stuck in a loop! **
+ iteration 1: $k=1; $v=v.1
--> State of array after loop:
-array(8) {
+array(4) {
[0]=>
- string(5) "new.5"
- [1]=>
- string(5) "new.4"
- [2]=>
- string(5) "new.3"
- [3]=>
- string(5) "new.2"
- [4]=>
string(5) "new.1"
- [5]=>
+ [1]=>
string(5) "new.0"
- [6]=>
+ [2]=>
string(3) "v.0"
- [7]=>
+ [3]=>
string(3) "v.1"
}
@@ -485,31 +439,21 @@ array(3) {
}
--> Do loop:
iteration 0: $k=0; $v=v.0
- iteration 1: $k=0; $v=new.0
- iteration 2: $k=0; $v=new.1
- iteration 3: $k=0; $v=new.2
- iteration 4: $k=0; $v=new.3
- iteration 5: $k=0; $v=new.4
- ** Stuck in a loop! **
+ iteration 1: $k=1; $v=v.1
+ iteration 2: $k=2; $v=v.2
--> State of array after loop:
-array(9) {
+array(6) {
[0]=>
- string(5) "new.5"
- [1]=>
- string(5) "new.4"
- [2]=>
- string(5) "new.3"
- [3]=>
string(5) "new.2"
- [4]=>
+ [1]=>
string(5) "new.1"
- [5]=>
+ [2]=>
string(5) "new.0"
- [6]=>
+ [3]=>
string(3) "v.0"
- [7]=>
+ [4]=>
string(3) "v.1"
- [8]=>
+ [5]=>
string(3) "v.2"
}
@@ -527,32 +471,25 @@ array(4) {
}
--> Do loop:
iteration 0: $k=0; $v=v.0
- iteration 1: $k=0; $v=new.0
- iteration 2: $k=0; $v=new.1
- iteration 3: $k=0; $v=new.2
- iteration 4: $k=0; $v=new.3
- iteration 5: $k=0; $v=new.4
- ** Stuck in a loop! **
+ iteration 1: $k=1; $v=v.1
+ iteration 2: $k=2; $v=v.2
+ iteration 3: $k=3; $v=v.3
--> State of array after loop:
-array(10) {
+array(8) {
[0]=>
- string(5) "new.5"
- [1]=>
- string(5) "new.4"
- [2]=>
string(5) "new.3"
- [3]=>
+ [1]=>
string(5) "new.2"
- [4]=>
+ [2]=>
string(5) "new.1"
- [5]=>
+ [3]=>
string(5) "new.0"
- [6]=>
+ [4]=>
string(3) "v.0"
- [7]=>
+ [5]=>
string(3) "v.1"
- [8]=>
+ [6]=>
string(3) "v.2"
- [9]=>
+ [7]=>
string(3) "v.3"
}
diff --git a/tests/lang/foreachLoopObjects.006.phpt b/tests/lang/foreachLoopObjects.006.phpt
index 8218b44dab..5204aca9ca 100644
--- a/tests/lang/foreachLoopObjects.006.phpt
+++ b/tests/lang/foreachLoopObjects.006.phpt
@@ -70,16 +70,12 @@ var_dump($obj);
?>
--EXPECTF--
-
Substituting the iterated object for a different object.
string(10) "Original a"
string(10) "Original b"
-string(5) "new a"
-string(5) "new b"
-string(5) "new c"
-string(5) "new d"
-string(5) "new e"
-string(5) "new f"
+string(10) "Original c"
+string(10) "Original d"
+string(10) "Original e"
object(stdClass)#%d (6) {
["a"]=>
string(5) "new a"
@@ -98,14 +94,9 @@ object(stdClass)#%d (6) {
Substituting the iterated object for an array.
string(10) "Original a"
string(10) "Original b"
-int(1)
-int(2)
-int(3)
-int(4)
-int(5)
-int(6)
-int(7)
-int(8)
+string(10) "Original c"
+string(10) "Original d"
+string(10) "Original e"
array(8) {
[0]=>
int(1)
@@ -128,11 +119,12 @@ array(8) {
Substituting the iterated array for an object.
int(1)
int(2)
-string(10) "Original a"
-string(10) "Original b"
-string(10) "Original c"
-string(10) "Original d"
-string(10) "Original e"
+int(3)
+int(4)
+int(5)
+int(6)
+int(7)
+int(8)
object(C)#%d (5) {
["a"]=>
string(10) "Original a"