summaryrefslogtreecommitdiff
path: root/Zend/zend_vm_def.h
diff options
context:
space:
mode:
Diffstat (limited to 'Zend/zend_vm_def.h')
-rw-r--r--Zend/zend_vm_def.h765
1 files changed, 489 insertions, 276 deletions
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index 24bb3fd3d6..80f7ef3c14 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -2138,6 +2138,21 @@ ZEND_VM_HANDLER(70, ZEND_FREE, TMPVAR, ANY)
ZEND_VM_NEXT_OPCODE();
}
+ZEND_VM_HANDLER(127, ZEND_FE_FREE, TMPVAR, ANY)
+{
+ zval *var;
+ USE_OPLINE
+
+ SAVE_OPLINE();
+ var = EX_VAR(opline->op1.var);
+ if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
+ zend_hash_iterator_del(Z_FE_ITER_P(var));
+ }
+ zval_ptr_dtor_nogc(var);
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
+}
+
ZEND_VM_HANDLER(54, ZEND_ADD_CHAR, TMP|UNUSED, CONST)
{
USE_OPLINE
@@ -3821,6 +3836,14 @@ ZEND_VM_HANDLER(100, ZEND_GOTO, ANY, CONST)
if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var));
}
+ } else if (brk_opline->opcode == ZEND_FE_FREE) {
+ if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
+ zval *var = EX_VAR(brk_opline->op1.var);
+ if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
+ zend_hash_iterator_del(Z_FE_ITER_P(var));
+ }
+ zval_ptr_dtor_nogc(var);
+ }
}
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op1));
}
@@ -4620,292 +4643,505 @@ 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, *result;
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) {
+ array_ptr = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R);
+ if (EXPECTED(Z_TYPE_P(array_ptr) == IS_ARRAY)) {
+ result = EX_VAR(opline->result.var);
+ ZVAL_COPY_VALUE(result, array_ptr);
+ if (OP1_TYPE != IS_TMP_VAR && Z_OPT_REFCOUNTED_P(result)) {
+ Z_ADDREF_P(array_ptr);
+ }
+ Z_FE_POS_P(result) = 0;
+
+ FREE_OP1_IF_VAR();
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
+ } else if (OP1_TYPE != IS_CONST && EXPECTED(Z_TYPE_P(array_ptr) == IS_OBJECT)) {
+ if (!Z_OBJCE_P(array_ptr)->get_iterator) {
+ HashPosition pos = 0;
+ Bucket *p;
+
+ result = EX_VAR(opline->result.var);
+ ZVAL_COPY_VALUE(result, array_ptr);
+ if (OP1_TYPE != IS_TMP_VAR) {
Z_ADDREF_P(array_ptr);
}
- array_ref = array_ptr;
+ fe_ht = Z_OBJPROP_P(array_ptr);
+ pos = 0;
+ while (1) {
+ if (pos >= fe_ht->nNumUsed) {
+ FREE_OP1_IF_VAR();
+ Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+ ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+ }
+ p = fe_ht->arData + pos;
+ if ((Z_TYPE(p->val) != IS_UNDEF &&
+ (Z_TYPE(p->val) != IS_INDIRECT ||
+ Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
+ (!p->key ||
+ zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
+ break;
+ }
+ pos++;
+ }
+ fe_ht->nInternalPointer = pos;
+ Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht, pos);
+
+ FREE_OP1_IF_VAR();
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
} 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);
- }
- 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);
+ zend_class_entry *ce = Z_OBJCE_P(array_ptr);
+ zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 0);
+ zend_bool is_empty;
+
+ if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
+ FREE_OP1();
+ if (!EG(exception)) {
+ zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
}
+ zend_throw_exception_internal(NULL);
+ HANDLE_EXCEPTION();
}
- } 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)) {
+ OBJ_RELEASE(&iter->std);
+ FREE_OP1();
+ 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);
+
+ is_empty = iter->funcs->valid(iter) != SUCCESS;
+
+ if (UNEXPECTED(EG(exception) != NULL)) {
+ OBJ_RELEASE(&iter->std);
+ FREE_OP1();
+ HANDLE_EXCEPTION();
+ }
+ iter->index = -1; /* will be set to 0 before using next handler */
+
+ ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
+ Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+
+ FREE_OP1();
+ if (is_empty) {
+ ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
} else {
- 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);
- }
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
}
}
+ } else {
+ zend_error(E_WARNING, "Invalid argument supplied for foreach()");
+ ZVAL_UNDEF(EX_VAR(opline->result.var));
+ Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+ FREE_OP1();
+ ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
}
+}
+
+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;
+ HashPosition pos = 0;
+ Bucket *p;
- if (ce && ce->get_iterator) {
- iter = ce->get_iterator(ce, array_ptr, opline->extended_value & ZEND_FE_FETCH_BYREF);
+ SAVE_OPLINE();
- if (OP1_TYPE == IS_VAR && !(opline->extended_value & ZEND_FE_FETCH_BYREF)) {
- FREE_OP1_IF_VAR();
+ if (OP1_TYPE == IS_VAR || OP1_TYPE == IS_CV) {
+ array_ref = array_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_R);
+ if (Z_ISREF_P(array_ref)) {
+ array_ptr = Z_REFVAL_P(array_ref);
+ }
+ } else {
+ array_ref = array_ptr = GET_OP1_ZVAL_PTR(BP_VAR_R);
+ }
+
+ if (EXPECTED(Z_TYPE_P(array_ptr) == IS_ARRAY)) {
+ if (OP1_TYPE == IS_VAR || OP1_TYPE == IS_CV) {
+ if (array_ptr == array_ref) {
+ ZVAL_NEW_REF(array_ref, array_ref);
+ array_ptr = Z_REFVAL_P(array_ref);
+ }
+ Z_ADDREF_P(array_ref);
+ ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref);
+ } else {
+ array_ptr = EX_VAR(opline->result.var);
+ ZVAL_COPY_VALUE(array_ptr, array_ref);
}
- if (iter && EXPECTED(EG(exception) == NULL)) {
- ZVAL_OBJ(&iterator, &iter->std);
- array_ptr = array_ref = &iterator;
+ if (OP1_TYPE == IS_CONST) {
+ zval_copy_ctor_func(array_ptr);
} else {
- if (OP1_TYPE == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
+ SEPARATE_ARRAY(array_ptr);
+ }
+ fe_ht = Z_ARRVAL_P(array_ptr);
+ while (1) {
+ if (pos >= fe_ht->nNumUsed) {
FREE_OP1_VAR_PTR();
+ Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+ ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
}
- if (!EG(exception)) {
- zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+ p = fe_ht->arData + pos;
+ if (Z_TYPE(p->val) != IS_UNDEF &&
+ (Z_TYPE(p->val) != IS_INDIRECT ||
+ Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) {
+ break;
}
- zend_throw_exception_internal(NULL);
- HANDLE_EXCEPTION();
+ pos++;
}
- }
+ fe_ht->nInternalPointer = pos;
+ Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht, pos);
+
+ FREE_OP1_VAR_PTR();
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
+ } else if (OP1_TYPE != IS_CONST && EXPECTED(Z_TYPE_P(array_ptr) == IS_OBJECT)) {
+ if (!Z_OBJCE_P(array_ptr)->get_iterator) {
+ if (OP1_TYPE == IS_VAR || OP1_TYPE == IS_CV) {
+ if (array_ptr == array_ref) {
+ ZVAL_NEW_REF(array_ref, array_ref);
+ array_ptr = Z_REFVAL_P(array_ref);
+ }
+ Z_ADDREF_P(array_ref);
+ ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref);
+ } else {
+ array_ptr = EX_VAR(opline->result.var);
+ ZVAL_COPY_VALUE(array_ptr, array_ref);
+ }
+ fe_ht = Z_OBJPROP_P(array_ptr);
+ while (1) {
+ if (pos >= fe_ht->nNumUsed) {
+ FREE_OP1_VAR_PTR();
+ Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+ ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+ }
+ p = fe_ht->arData + pos;
+ if ((Z_TYPE(p->val) != IS_UNDEF &&
+ (Z_TYPE(p->val) != IS_INDIRECT ||
+ Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
+ (!p->key ||
+ zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
+ break;
+ }
+ pos++;
+ }
+ fe_ht->nInternalPointer = pos;
+ Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht, pos);
+
+ FREE_OP1_VAR_PTR();
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
+ } else {
+ zend_class_entry *ce = Z_OBJCE_P(array_ptr);
+ zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 1);
+ zend_bool is_empty;
+
+ if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
+ if (OP1_TYPE == IS_VAR) {
+ FREE_OP1_VAR_PTR();
+ } else {
+ FREE_OP1();
+ }
+ if (!EG(exception)) {
+ zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+ }
+ zend_throw_exception_internal(NULL);
+ HANDLE_EXCEPTION();
+ }
- ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref);
+ iter->index = 0;
+ if (iter->funcs->rewind) {
+ iter->funcs->rewind(iter);
+ if (UNEXPECTED(EG(exception) != NULL)) {
+ OBJ_RELEASE(&iter->std);
+ if (OP1_TYPE == IS_VAR) {
+ FREE_OP1_VAR_PTR();
+ } else {
+ FREE_OP1();
+ }
+ HANDLE_EXCEPTION();
+ }
+ }
+
+ is_empty = iter->funcs->valid(iter) != SUCCESS;
- if (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) {
+ OBJ_RELEASE(&iter->std);
+ if (OP1_TYPE == IS_VAR) {
FREE_OP1_VAR_PTR();
+ } else {
+ FREE_OP1();
}
HANDLE_EXCEPTION();
}
- }
- is_empty = iter->funcs->valid(iter) != SUCCESS;
- if (UNEXPECTED(EG(exception) != NULL)) {
- zval_ptr_dtor(array_ref);
- if (OP1_TYPE == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
+ iter->index = -1; /* will be set to 0 before using next handler */
+
+ ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
+ Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+
+ if (OP1_TYPE == IS_VAR) {
FREE_OP1_VAR_PTR();
+ } else {
+ FREE_OP1();
}
- HANDLE_EXCEPTION();
+ if (is_empty) {
+ ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+ } else {
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
+ }
+ }
+ } else {
+ zend_error(E_WARNING, "Invalid argument supplied for foreach()");
+ ZVAL_UNDEF(EX_VAR(opline->result.var));
+ Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+ if (OP1_TYPE == IS_VAR) {
+ FREE_OP1_VAR_PTR();
+ } else {
+ FREE_OP1();
}
- iter->index = -1; /* will be set to 0 before using next handler */
- } else if ((fe_ht = HASH_OF(array_ptr)) != NULL) {
- HashPointer *ptr = (HashPointer*)EX_VAR((opline+2)->op1.var);
- HashPosition pos = 0;
- Bucket *p;
+ ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+ }
+}
+
+ZEND_VM_HANDLER(78, ZEND_FE_FETCH_R, 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();
+ 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 (pos >= fe_ht->nNumUsed) {
- is_empty = 1;
- if (OP1_TYPE == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
- FREE_OP1_VAR_PTR();
- }
+ if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
+ /* reached end of iteration */
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)) {
+ 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 (!ce ||
- !p->key ||
- zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS) {
- break;
+ 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);
}
- 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;
+ 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 = zend_hash_iterator_pos(Z_FE_ITER_P(EX_VAR(opline->op1.var)), fe_ht);
+ while (1) {
+ if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
+ /* reached end of iteration */
+ 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);
+ while (1) {
+ pos++;
+ if (pos >= fe_ht->nNumUsed) {
+ pos = INVALID_IDX;
+ break;
+ }
+ p = fe_ht->arData + pos;
+ if ((Z_TYPE(p->val) != IS_UNDEF &&
+ (Z_TYPE(p->val) != IS_INDIRECT ||
+ Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
+ (Z_TYPE_P(array) != IS_OBJECT ||
+ !p->key ||
+ zend_check_property_access(Z_OBJ_P(array), p->key) == SUCCESS)) {
+ break;
+ }
+ }
+ EG(ht_iterators)[Z_FE_ITER_P(EX_VAR(opline->op1.var))].pos =
+ fe_ht->nInternalPointer = pos;
+ ZEND_VM_INC_OPCODE();
+ ZEND_VM_NEXT_OPCODE();
+ } else {
+ /* !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()");
- is_empty = 1;
- }
-
- 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();
}
}
-ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY)
+ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, 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();
+ 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;
- 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);
- }
- }
- }
+ pos = zend_hash_iterator_pos(Z_FE_ITER_P(EX_VAR(opline->op1.var)), fe_ht);
while (1) {
if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
/* reached end of iteration */
+ 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);
- }
- 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);
- }
+ 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;
+ }
+ }
+ EG(ht_iterators)[Z_FE_ITER_P(EX_VAR(opline->op1.var))].pos =
+ fe_ht->nInternalPointer = pos;
ZEND_VM_INC_OPCODE();
ZEND_VM_NEXT_OPCODE();
} else if (EXPECTED(Z_TYPE_P(array) == IS_OBJECT)) {
@@ -4916,93 +5152,66 @@ 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) {
- /* 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);
- }
- }
- }
+ pos = zend_hash_iterator_pos(Z_FE_ITER_P(EX_VAR(opline->op1.var)), fe_ht);
while (1) {
if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
/* reached end of iteration */
+ 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;
+ }
+ }
+ EG(ht_iterators)[Z_FE_ITER_P(EX_VAR(opline->op1.var))].pos =
+ fe_ht->nInternalPointer = pos;
ZEND_VM_INC_OPCODE();
ZEND_VM_NEXT_OPCODE();
} else {
@@ -5012,7 +5221,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,38 +5229,34 @@ 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) {
+ 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 {
ZVAL_LONG(EX_VAR((opline+1)->result.var), iter->index);
}
}
+ ZVAL_MAKE_REF(value);
+ Z_ADDREF_P(value);
+ ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
ZEND_VM_INC_OPCODE();
ZEND_VM_NEXT_OPCODE();
}
@@ -5840,6 +6045,14 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var));
}
+ } else if (brk_opline->opcode == ZEND_FE_FREE) {
+ if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
+ zval *var = EX_VAR(brk_opline->op1.var);
+ if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
+ zend_hash_iterator_del(Z_FE_ITER_P(var));
+ }
+ zval_ptr_dtor_nogc(var);
+ }
} else if (brk_opline->opcode == ZEND_END_SILENCE) {
/* restore previous error_reporting value */
if (!EG(error_reporting) && Z_LVAL_P(EX_VAR(brk_opline->op1.var)) != 0) {