mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
Reimplement iteration magic with HashTableIterators (see https://wiki.php.net/rfc/php7_foreach#implementation_details)
This commit is contained in:
@@ -829,7 +829,7 @@ static int generate_free_loop_var(znode *var) /* {{{ */
|
||||
{
|
||||
zend_op *opline = get_next_op(CG(active_op_array));
|
||||
|
||||
opline->opcode = ZEND_FREE;
|
||||
opline->opcode = var->flag ? ZEND_FE_FREE : ZEND_FREE;
|
||||
SET_NODE(opline->op1, var);
|
||||
SET_UNUSED(opline->op2);
|
||||
}
|
||||
@@ -3398,6 +3398,7 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */
|
||||
opnum_reset = get_next_op_number(CG(active_op_array));
|
||||
opline = zend_emit_op(&reset_node, by_ref ? ZEND_FE_RESET_RW : ZEND_FE_RESET_R, &expr_node, NULL);
|
||||
|
||||
reset_node.flag = by_ref;
|
||||
zend_stack_push(&CG(loop_var_stack), &reset_node);
|
||||
|
||||
opnum_fetch = get_next_op_number(CG(active_op_array));
|
||||
@@ -3408,12 +3409,6 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */
|
||||
|
||||
opline = zend_emit_op(NULL, ZEND_OP_DATA, NULL, NULL);
|
||||
|
||||
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) {
|
||||
zend_make_tmp_result(&key_node, opline);
|
||||
}
|
||||
@@ -3504,6 +3499,7 @@ void zend_compile_switch(zend_ast *ast) /* {{{ */
|
||||
|
||||
zend_compile_expr(&expr_node, expr_ast);
|
||||
|
||||
expr_node.flag = 0;
|
||||
zend_stack_push(&CG(loop_var_stack), &expr_node);
|
||||
|
||||
zend_begin_loop();
|
||||
|
||||
@@ -95,7 +95,8 @@ typedef union _znode_op {
|
||||
} znode_op;
|
||||
|
||||
typedef struct _znode { /* used only during compilation */
|
||||
int op_type;
|
||||
zend_uchar op_type;
|
||||
zend_uchar flag;
|
||||
union {
|
||||
znode_op op;
|
||||
zval constant; /* replaced by literal/zv */
|
||||
|
||||
@@ -1584,6 +1584,14 @@ static inline zend_brk_cont_element* zend_brk_cont(int nest_levels, int array_of
|
||||
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_FE_ITER_P(var) != (uint32_t)-1) {
|
||||
zend_hash_iterator_del(Z_FE_ITER_P(var));
|
||||
}
|
||||
zval_ptr_dtor_nogc(var);
|
||||
}
|
||||
}
|
||||
}
|
||||
array_offset = jmp_to->parent;
|
||||
|
||||
@@ -183,6 +183,11 @@ void init_executor(void) /* {{{ */
|
||||
|
||||
EG(scope) = NULL;
|
||||
|
||||
EG(ht_iterators_count) = sizeof(EG(ht_iterators_slots)) / sizeof(HashTableIterator);
|
||||
EG(ht_iterators_used) = 0;
|
||||
EG(ht_iterators) = EG(ht_iterators_slots);
|
||||
memset(EG(ht_iterators), 0, sizeof(EG(ht_iterators_slots)));
|
||||
|
||||
EG(active) = 1;
|
||||
}
|
||||
/* }}} */
|
||||
@@ -373,6 +378,11 @@ void shutdown_executor(void) /* {{{ */
|
||||
|
||||
zend_shutdown_fpu();
|
||||
|
||||
EG(ht_iterators_used) = 0;
|
||||
if (EG(ht_iterators) != EG(ht_iterators_slots)) {
|
||||
efree(EG(ht_iterators));
|
||||
}
|
||||
|
||||
EG(active) = 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -60,6 +60,12 @@ static void zend_generator_cleanup_unfinished_execution(zend_generator *generato
|
||||
if (brk_opline->opcode == ZEND_FREE) {
|
||||
zval *var = EX_VAR(brk_opline->op1.var);
|
||||
zval_ptr_dtor_nogc(var);
|
||||
} else if (brk_opline->opcode == ZEND_FE_FREE) {
|
||||
zval *var = EX_VAR(brk_opline->op1.var);
|
||||
if (Z_FE_ITER_P(var) != (uint32_t)-1) {
|
||||
zend_hash_iterator_del(Z_FE_ITER_P(var));
|
||||
}
|
||||
zval_ptr_dtor_nogc(var);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,6 +225,11 @@ struct _zend_executor_globals {
|
||||
zend_bool active;
|
||||
zend_bool valid_symbol_table;
|
||||
|
||||
uint32_t ht_iterators_count; /* number of allocatd slots */
|
||||
uint32_t ht_iterators_used; /* number of used slots */
|
||||
HashTableIterator *ht_iterators;
|
||||
HashTableIterator ht_iterators_slots[16];
|
||||
|
||||
void *saved_fpu_cw_ptr;
|
||||
#if XPFPA_HAVE_CW
|
||||
XPFPA_CW_DATATYPE saved_fpu_cw;
|
||||
|
||||
147
Zend/zend_hash.c
147
Zend/zend_hash.c
@@ -193,6 +193,144 @@ ZEND_API void zend_hash_set_apply_protection(HashTable *ht, zend_bool bApplyProt
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_API uint32_t zend_hash_iterator_add(HashTable *ht)
|
||||
{
|
||||
HashTableIterator *iter = EG(ht_iterators);
|
||||
HashTableIterator *end = iter + EG(ht_iterators_count);
|
||||
uint32_t idx;
|
||||
|
||||
if (EXPECTED(ht->u.v.nIteratorsCount != 255)) {
|
||||
ht->u.v.nIteratorsCount++;
|
||||
}
|
||||
while (iter != end) {
|
||||
if (iter->ht == NULL) {
|
||||
iter->ht = ht;
|
||||
iter->pos = ht->nInternalPointer;
|
||||
idx = iter - EG(ht_iterators);
|
||||
if (idx + 1 > EG(ht_iterators_used)) {
|
||||
EG(ht_iterators_used) = idx + 1;
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
if (EG(ht_iterators) == EG(ht_iterators_slots)) {
|
||||
EG(ht_iterators) = emalloc(sizeof(HashTableIterator) * (EG(ht_iterators_count) + 8));
|
||||
memcpy(EG(ht_iterators), EG(ht_iterators_slots), sizeof(HashTableIterator) * EG(ht_iterators_count));
|
||||
} else {
|
||||
EG(ht_iterators) = erealloc(EG(ht_iterators), sizeof(HashTableIterator) * (EG(ht_iterators_count) + 8));
|
||||
}
|
||||
iter = EG(ht_iterators) + EG(ht_iterators_count);
|
||||
EG(ht_iterators_count) += 8;
|
||||
iter->ht = ht;
|
||||
iter->pos = ht->nInternalPointer;
|
||||
memset(iter + 1, 0, sizeof(HashTableIterator) * 7);
|
||||
idx = iter - EG(ht_iterators);
|
||||
EG(ht_iterators_used) = idx + 1;
|
||||
return idx;
|
||||
}
|
||||
|
||||
ZEND_API HashPosition zend_hash_iterator_pos(uint32_t idx, HashTable *ht)
|
||||
{
|
||||
HashTableIterator *iter = EG(ht_iterators) + idx;
|
||||
|
||||
ZEND_ASSERT(idx != (uint32_t)-1);
|
||||
if (iter->pos == INVALID_IDX) {
|
||||
return INVALID_IDX;
|
||||
} else if (UNEXPECTED(iter->ht != ht)) {
|
||||
if (EXPECTED(iter->ht) && EXPECTED(iter->ht->u.v.nIteratorsCount != 255)) {
|
||||
iter->ht->u.v.nIteratorsCount--;
|
||||
}
|
||||
if (EXPECTED(ht->u.v.nIteratorsCount != 255)) {
|
||||
ht->u.v.nIteratorsCount++;
|
||||
}
|
||||
iter->ht = ht;
|
||||
iter->pos = ht->nInternalPointer;
|
||||
}
|
||||
return iter->pos;
|
||||
}
|
||||
|
||||
ZEND_API void zend_hash_iterator_del(uint32_t idx)
|
||||
{
|
||||
HashTableIterator *iter = EG(ht_iterators) + idx;
|
||||
|
||||
ZEND_ASSERT(idx != (uint32_t)-1);
|
||||
|
||||
if (EXPECTED(iter->ht) && EXPECTED(iter->ht->u.v.nIteratorsCount != 255)) {
|
||||
iter->ht->u.v.nIteratorsCount--;
|
||||
}
|
||||
iter->ht = NULL;
|
||||
|
||||
if (idx == EG(ht_iterators_used) - 1) {
|
||||
while (idx > 0 && EG(ht_iterators)[idx - 1].ht == NULL) {
|
||||
idx--;
|
||||
}
|
||||
EG(ht_iterators_used) = idx;
|
||||
}
|
||||
}
|
||||
|
||||
static zend_never_inline void _iterators_del(HashTable *ht)
|
||||
{
|
||||
HashTableIterator *iter = EG(ht_iterators);
|
||||
HashTableIterator *end = iter + EG(ht_iterators_used);
|
||||
uint32_t idx;
|
||||
|
||||
while (iter != end) {
|
||||
if (iter->ht == ht) {
|
||||
iter->ht = NULL;
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
|
||||
idx = EG(ht_iterators_used);
|
||||
while (idx > 0 && EG(ht_iterators)[idx - 1].ht == NULL) {
|
||||
idx--;
|
||||
}
|
||||
EG(ht_iterators_used) = idx;
|
||||
}
|
||||
|
||||
static zend_always_inline void iterators_del(HashTable *ht)
|
||||
{
|
||||
if (UNEXPECTED(ht->u.v.nIteratorsCount)) {
|
||||
_iterators_del(ht);
|
||||
}
|
||||
}
|
||||
|
||||
static zend_never_inline void _iterators_update(HashTable *ht, HashPosition pos)
|
||||
{
|
||||
HashTableIterator *iter = EG(ht_iterators);
|
||||
HashTableIterator *end = iter + EG(ht_iterators_used);
|
||||
|
||||
while (iter != end) {
|
||||
if (iter->ht == ht && iter->pos == ht->nInternalPointer) {
|
||||
iter->pos = pos;
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
static zend_always_inline void iterators_update(HashTable *ht, HashPosition pos)
|
||||
{
|
||||
if (UNEXPECTED(ht->u.v.nIteratorsCount)) {
|
||||
_iterators_update(ht, pos);
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_API void zend_hash_iterators_update(HashTable *ht, HashPosition pos)
|
||||
{
|
||||
if (UNEXPECTED(ht->u.v.nIteratorsCount)) {
|
||||
HashTableIterator *iter = EG(ht_iterators);
|
||||
HashTableIterator *end = iter + EG(ht_iterators_used);
|
||||
|
||||
while (iter != end) {
|
||||
if (iter->ht == ht && iter->pos == ht->nInternalPointer) {
|
||||
iter->pos = pos;
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static zend_always_inline Bucket *zend_hash_find_bucket(const HashTable *ht, zend_string *key)
|
||||
{
|
||||
zend_ulong h;
|
||||
@@ -303,6 +441,7 @@ add_to_hash:
|
||||
idx = ht->nNumUsed++;
|
||||
ht->nNumOfElements++;
|
||||
if (ht->nInternalPointer == INVALID_IDX) {
|
||||
iterators_update(ht, idx);
|
||||
ht->nInternalPointer = idx;
|
||||
}
|
||||
p = ht->arData + idx;
|
||||
@@ -470,6 +609,7 @@ add_to_packed:
|
||||
}
|
||||
ht->nNumOfElements++;
|
||||
if (ht->nInternalPointer == INVALID_IDX) {
|
||||
iterators_update(ht, h);
|
||||
ht->nInternalPointer = h;
|
||||
}
|
||||
if ((zend_long)h >= (zend_long)ht->nNextFreeElement) {
|
||||
@@ -512,6 +652,7 @@ add_to_hash:
|
||||
idx = ht->nNumUsed++;
|
||||
ht->nNumOfElements++;
|
||||
if (ht->nInternalPointer == INVALID_IDX) {
|
||||
iterators_update(ht, idx);
|
||||
ht->nInternalPointer = idx;
|
||||
}
|
||||
if ((zend_long)h >= (zend_long)ht->nNextFreeElement) {
|
||||
@@ -600,6 +741,7 @@ ZEND_API int zend_hash_rehash(HashTable *ht)
|
||||
if (i != j) {
|
||||
ht->arData[j] = ht->arData[i];
|
||||
if (ht->nInternalPointer == i) {
|
||||
iterators_update(ht, j);
|
||||
ht->nInternalPointer = j;
|
||||
}
|
||||
}
|
||||
@@ -632,9 +774,11 @@ static zend_always_inline void _zend_hash_del_el_ex(HashTable *ht, uint32_t idx,
|
||||
while (1) {
|
||||
idx++;
|
||||
if (idx >= ht->nNumUsed) {
|
||||
iterators_update(ht, INVALID_IDX);
|
||||
ht->nInternalPointer = INVALID_IDX;
|
||||
break;
|
||||
} else if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
|
||||
iterators_update(ht, idx);
|
||||
ht->nInternalPointer = idx;
|
||||
break;
|
||||
}
|
||||
@@ -893,6 +1037,7 @@ ZEND_API void zend_hash_destroy(HashTable *ht)
|
||||
} while (++p != end);
|
||||
}
|
||||
}
|
||||
iterators_del(ht);
|
||||
} else if (EXPECTED(!(ht->u.flags & HASH_FLAG_INITIALIZED))) {
|
||||
return;
|
||||
}
|
||||
@@ -933,7 +1078,7 @@ ZEND_API void zend_array_destroy(HashTable *ht)
|
||||
}
|
||||
} while (++p != end);
|
||||
}
|
||||
|
||||
iterators_del(ht);
|
||||
SET_INCONSISTENT(HT_DESTROYED);
|
||||
} else if (EXPECTED(!(ht->u.flags & HASH_FLAG_INITIALIZED))) {
|
||||
return;
|
||||
|
||||
@@ -50,8 +50,6 @@ typedef struct _zend_hash_key {
|
||||
|
||||
typedef zend_bool (*merge_checker_func_t)(HashTable *target_ht, zval *source_data, zend_hash_key *hash_key, void *pParam);
|
||||
|
||||
typedef uint32_t HashPosition;
|
||||
|
||||
BEGIN_EXTERN_C()
|
||||
|
||||
/* startup/shutdown */
|
||||
@@ -227,6 +225,13 @@ void zend_hash_display(const HashTable *ht);
|
||||
|
||||
ZEND_API int _zend_handle_numeric_str_ex(const char *key, size_t length, zend_ulong *idx);
|
||||
|
||||
|
||||
ZEND_API uint32_t zend_hash_iterator_add(HashTable *ht);
|
||||
ZEND_API HashPosition zend_hash_iterator_pos(uint32_t idx, HashTable *ht);
|
||||
ZEND_API void zend_hash_iterator_del(uint32_t idx);
|
||||
ZEND_API void zend_hash_iterators_update(HashTable *ht, HashPosition pos);
|
||||
|
||||
|
||||
END_EXTERN_C()
|
||||
|
||||
#define ZEND_INIT_SYMTABLE(ht) \
|
||||
|
||||
@@ -129,6 +129,7 @@ struct _zval_struct {
|
||||
uint32_t lineno; /* line number (for ast nodes) */
|
||||
uint32_t num_args; /* arguments number for EX(This) */
|
||||
uint32_t fe_pos; /* foreach position */
|
||||
uint32_t fe_iter_idx; /* foreach iterator index */
|
||||
} u2;
|
||||
};
|
||||
|
||||
@@ -161,10 +162,11 @@ typedef struct _Bucket {
|
||||
typedef struct _HashTable {
|
||||
union {
|
||||
struct {
|
||||
ZEND_ENDIAN_LOHI_3(
|
||||
ZEND_ENDIAN_LOHI_4(
|
||||
zend_uchar flags,
|
||||
zend_uchar nApplyCount,
|
||||
uint16_t reserve)
|
||||
zend_uchar nIteratorsCount,
|
||||
zend_uchar reserve)
|
||||
} v;
|
||||
uint32_t flags;
|
||||
} u;
|
||||
@@ -179,6 +181,13 @@ typedef struct _HashTable {
|
||||
dtor_func_t pDestructor;
|
||||
} HashTable;
|
||||
|
||||
typedef uint32_t HashPosition;
|
||||
|
||||
typedef struct _HashTableIterator {
|
||||
HashTable *ht;
|
||||
HashPosition pos;
|
||||
} HashTableIterator;
|
||||
|
||||
struct _zend_array {
|
||||
zend_refcounted gc;
|
||||
HashTable ht;
|
||||
@@ -265,6 +274,9 @@ static zend_always_inline zend_uchar zval_get_type(const zval* pz) {
|
||||
#define Z_FE_POS(zval) (zval).u2.fe_pos
|
||||
#define Z_FE_POS_P(zval_p) Z_FE_POS(*(zval_p))
|
||||
|
||||
#define Z_FE_ITER(zval) (zval).u2.fe_iter_idx
|
||||
#define Z_FE_ITER_P(zval_p) Z_FE_ITER(*(zval_p))
|
||||
|
||||
#define Z_COUNTED(zval) (zval).value.counted
|
||||
#define Z_COUNTED_P(zval_p) Z_COUNTED(*(zval_p))
|
||||
|
||||
|
||||
@@ -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_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_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));
|
||||
}
|
||||
@@ -4758,8 +4781,7 @@ ZEND_VM_HANDLER(125, ZEND_FE_RESET_RW, CONST|TMP|VAR|CV, ANY)
|
||||
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);
|
||||
Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
|
||||
|
||||
if (OP1_TYPE == IS_VAR) {
|
||||
FREE_OP1_VAR_PTR();
|
||||
@@ -4798,6 +4820,7 @@ ZEND_VM_HANDLER(125, ZEND_FE_RESET_RW, CONST|TMP|VAR|CV, ANY)
|
||||
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;
|
||||
@@ -4811,8 +4834,8 @@ ZEND_VM_HANDLER(125, ZEND_FE_RESET_RW, CONST|TMP|VAR|CV, ANY)
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
Z_FE_POS_P(EX_VAR(opline->result.var)) = fe_ht->nInternalPointer = pos;
|
||||
ZVAL_PTR(EX_VAR((opline+2)->op1.var), fe_ht);
|
||||
fe_ht->nInternalPointer = pos;
|
||||
Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht);
|
||||
|
||||
FREE_OP1_VAR_PTR();
|
||||
CHECK_EXCEPTION();
|
||||
@@ -4820,6 +4843,7 @@ ZEND_VM_HANDLER(125, ZEND_FE_RESET_RW, CONST|TMP|VAR|CV, ANY)
|
||||
} 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 {
|
||||
@@ -4990,21 +5014,7 @@ ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY)
|
||||
ZVAL_DEREF(array);
|
||||
if (EXPECTED(Z_TYPE_P(array) == IS_ARRAY)) {
|
||||
fe_ht = Z_ARRVAL_P(array);
|
||||
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 (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) {
|
||||
//??? //...
|
||||
//??? }
|
||||
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 */
|
||||
@@ -5048,7 +5058,8 @@ ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY)
|
||||
break;
|
||||
}
|
||||
}
|
||||
Z_FE_POS_P(EX_VAR(opline->op1.var)) = fe_ht->nInternalPointer = pos;
|
||||
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)) {
|
||||
@@ -5059,19 +5070,7 @@ ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY)
|
||||
zend_object *zobj = Z_OBJ_P(array);
|
||||
|
||||
fe_ht = Z_OBJPROP_P(array);
|
||||
pos = Z_FE_POS_P(EX_VAR(opline->op1.var));
|
||||
if (UNEXPECTED(pos == INVALID_IDX)) {
|
||||
/* reached end of iteration */
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
} 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) {
|
||||
//???
|
||||
//??? }
|
||||
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 */
|
||||
@@ -5129,7 +5128,8 @@ ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY)
|
||||
break;
|
||||
}
|
||||
}
|
||||
Z_FE_POS_P(EX_VAR(opline->op1.var)) = fe_ht->nInternalPointer = pos;
|
||||
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 {
|
||||
@@ -5963,6 +5963,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_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) {
|
||||
|
||||
@@ -1347,6 +1347,14 @@ static int ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER
|
||||
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_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) {
|
||||
@@ -1805,6 +1813,14 @@ static int ZEND_FASTCALL ZEND_GOTO_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
|
||||
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_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));
|
||||
}
|
||||
@@ -3175,8 +3191,7 @@ static int ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLE
|
||||
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);
|
||||
Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
|
||||
|
||||
if (IS_CONST == IS_VAR) {
|
||||
|
||||
@@ -3215,6 +3230,7 @@ static int ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLE
|
||||
while (1) {
|
||||
if (pos >= fe_ht->nNumUsed) {
|
||||
|
||||
Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
}
|
||||
p = fe_ht->arData + pos;
|
||||
@@ -3228,14 +3244,15 @@ static int ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLE
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
Z_FE_POS_P(EX_VAR(opline->result.var)) = fe_ht->nInternalPointer = pos;
|
||||
ZVAL_PTR(EX_VAR((opline+2)->op1.var), fe_ht);
|
||||
fe_ht->nInternalPointer = pos;
|
||||
Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht);
|
||||
|
||||
CHECK_EXCEPTION();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
} else {
|
||||
zend_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 (IS_CONST == IS_VAR) {
|
||||
|
||||
} else {
|
||||
@@ -9109,8 +9126,7 @@ static int ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_
|
||||
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);
|
||||
Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
|
||||
|
||||
if (IS_TMP_VAR == IS_VAR) {
|
||||
|
||||
@@ -9149,6 +9165,7 @@ static int ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_
|
||||
while (1) {
|
||||
if (pos >= fe_ht->nNumUsed) {
|
||||
|
||||
Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
}
|
||||
p = fe_ht->arData + pos;
|
||||
@@ -9162,14 +9179,15 @@ static int ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
Z_FE_POS_P(EX_VAR(opline->result.var)) = fe_ht->nInternalPointer = pos;
|
||||
ZVAL_PTR(EX_VAR((opline+2)->op1.var), fe_ht);
|
||||
fe_ht->nInternalPointer = pos;
|
||||
Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht);
|
||||
|
||||
CHECK_EXCEPTION();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
} else {
|
||||
zend_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 (IS_TMP_VAR == IS_VAR) {
|
||||
|
||||
} else {
|
||||
@@ -11945,8 +11963,7 @@ static int ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_
|
||||
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);
|
||||
Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
|
||||
|
||||
if (IS_VAR == IS_VAR) {
|
||||
if (free_op1) {zval_ptr_dtor_nogc(free_op1);};
|
||||
@@ -11985,6 +12002,7 @@ static int ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_
|
||||
while (1) {
|
||||
if (pos >= fe_ht->nNumUsed) {
|
||||
if (free_op1) {zval_ptr_dtor_nogc(free_op1);};
|
||||
Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
}
|
||||
p = fe_ht->arData + pos;
|
||||
@@ -11998,8 +12016,8 @@ static int ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
Z_FE_POS_P(EX_VAR(opline->result.var)) = fe_ht->nInternalPointer = pos;
|
||||
ZVAL_PTR(EX_VAR((opline+2)->op1.var), fe_ht);
|
||||
fe_ht->nInternalPointer = pos;
|
||||
Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht);
|
||||
|
||||
if (free_op1) {zval_ptr_dtor_nogc(free_op1);};
|
||||
CHECK_EXCEPTION();
|
||||
@@ -12007,6 +12025,7 @@ static int ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_
|
||||
} 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 (IS_VAR == IS_VAR) {
|
||||
if (free_op1) {zval_ptr_dtor_nogc(free_op1);};
|
||||
} else {
|
||||
@@ -12177,21 +12196,7 @@ static int ZEND_FASTCALL ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_
|
||||
ZVAL_DEREF(array);
|
||||
if (EXPECTED(Z_TYPE_P(array) == IS_ARRAY)) {
|
||||
fe_ht = Z_ARRVAL_P(array);
|
||||
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 (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) {
|
||||
//??? //...
|
||||
//??? }
|
||||
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 */
|
||||
@@ -12235,7 +12240,8 @@ static int ZEND_FASTCALL ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_
|
||||
break;
|
||||
}
|
||||
}
|
||||
Z_FE_POS_P(EX_VAR(opline->op1.var)) = fe_ht->nInternalPointer = pos;
|
||||
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)) {
|
||||
@@ -12246,19 +12252,7 @@ static int ZEND_FASTCALL ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_
|
||||
zend_object *zobj = Z_OBJ_P(array);
|
||||
|
||||
fe_ht = Z_OBJPROP_P(array);
|
||||
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 (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) {
|
||||
//???
|
||||
//??? }
|
||||
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 */
|
||||
@@ -12316,7 +12310,8 @@ static int ZEND_FASTCALL ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_
|
||||
break;
|
||||
}
|
||||
}
|
||||
Z_FE_POS_P(EX_VAR(opline->op1.var)) = fe_ht->nInternalPointer = pos;
|
||||
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 {
|
||||
@@ -24354,8 +24349,7 @@ static int ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_A
|
||||
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);
|
||||
Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
|
||||
|
||||
if (IS_CV == IS_VAR) {
|
||||
|
||||
@@ -24394,6 +24388,7 @@ static int ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_A
|
||||
while (1) {
|
||||
if (pos >= fe_ht->nNumUsed) {
|
||||
|
||||
Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
}
|
||||
p = fe_ht->arData + pos;
|
||||
@@ -24407,14 +24402,15 @@ static int ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_A
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
Z_FE_POS_P(EX_VAR(opline->result.var)) = fe_ht->nInternalPointer = pos;
|
||||
ZVAL_PTR(EX_VAR((opline+2)->op1.var), fe_ht);
|
||||
fe_ht->nInternalPointer = pos;
|
||||
Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht);
|
||||
|
||||
CHECK_EXCEPTION();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
} else {
|
||||
zend_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 (IS_CV == IS_VAR) {
|
||||
|
||||
} else {
|
||||
@@ -33144,6 +33140,21 @@ static int ZEND_FASTCALL ZEND_FREE_SPEC_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
}
|
||||
|
||||
static int ZEND_FASTCALL ZEND_FE_FREE_SPEC_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
|
||||
{
|
||||
zval *var;
|
||||
USE_OPLINE
|
||||
|
||||
SAVE_OPLINE();
|
||||
var = EX_VAR(opline->op1.var);
|
||||
if (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();
|
||||
}
|
||||
|
||||
static int ZEND_FASTCALL ZEND_BOOL_SPEC_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
|
||||
{
|
||||
USE_OPLINE
|
||||
@@ -39719,16 +39730,16 @@ 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_FE_FREE_SPEC_TMPVAR_HANDLER,
|
||||
ZEND_FE_FREE_SPEC_TMPVAR_HANDLER,
|
||||
ZEND_FE_FREE_SPEC_TMPVAR_HANDLER,
|
||||
ZEND_FE_FREE_SPEC_TMPVAR_HANDLER,
|
||||
ZEND_FE_FREE_SPEC_TMPVAR_HANDLER,
|
||||
ZEND_FE_FREE_SPEC_TMPVAR_HANDLER,
|
||||
ZEND_FE_FREE_SPEC_TMPVAR_HANDLER,
|
||||
ZEND_FE_FREE_SPEC_TMPVAR_HANDLER,
|
||||
ZEND_FE_FREE_SPEC_TMPVAR_HANDLER,
|
||||
ZEND_FE_FREE_SPEC_TMPVAR_HANDLER,
|
||||
ZEND_NULL_HANDLER,
|
||||
ZEND_NULL_HANDLER,
|
||||
ZEND_NULL_HANDLER,
|
||||
|
||||
@@ -149,7 +149,7 @@ const char *zend_vm_opcodes_map[170] = {
|
||||
"ZEND_VERIFY_RETURN_TYPE",
|
||||
"ZEND_FE_RESET_RW",
|
||||
"ZEND_FE_FETCH_RW",
|
||||
NULL,
|
||||
"ZEND_FE_FREE",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
@@ -151,6 +151,7 @@ END_EXTERN_C()
|
||||
#define ZEND_VERIFY_RETURN_TYPE 124
|
||||
#define ZEND_FE_RESET_RW 125
|
||||
#define ZEND_FE_FETCH_RW 126
|
||||
#define ZEND_FE_FREE 127
|
||||
#define ZEND_PRE_INC_OBJ 132
|
||||
#define ZEND_PRE_DEC_OBJ 133
|
||||
#define ZEND_POST_INC_OBJ 134
|
||||
|
||||
@@ -207,12 +207,15 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimiz
|
||||
for (i = 0; i< op_array->last_brk_cont; i++) {
|
||||
if (op_array->brk_cont_array[i].start >= 0 &&
|
||||
(op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FREE ||
|
||||
op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FE_FREE ||
|
||||
op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_END_SILENCE)) {
|
||||
int parent = op_array->brk_cont_array[i].parent;
|
||||
|
||||
while (parent >= 0 &&
|
||||
op_array->brk_cont_array[parent].start < 0 &&
|
||||
op_array->opcodes[op_array->brk_cont_array[parent].brk].opcode != ZEND_FREE) {
|
||||
(op_array->opcodes[op_array->brk_cont_array[parent].brk].opcode != ZEND_FREE ||
|
||||
op_array->opcodes[op_array->brk_cont_array[parent].brk].opcode != ZEND_FE_FREE ||
|
||||
op_array->opcodes[op_array->brk_cont_array[parent].brk].opcode != ZEND_END_SILENCE)) {
|
||||
parent = op_array->brk_cont_array[parent].parent;
|
||||
}
|
||||
op_array->brk_cont_array[i].parent = parent;
|
||||
@@ -227,6 +230,7 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimiz
|
||||
for (i = 0; i< op_array->last_brk_cont; i++) {
|
||||
if (op_array->brk_cont_array[i].start >= 0 &&
|
||||
(op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FREE ||
|
||||
op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FE_FREE ||
|
||||
op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_END_SILENCE)) {
|
||||
if (i != j) {
|
||||
op_array->brk_cont_array[j] = op_array->brk_cont_array[i];
|
||||
|
||||
@@ -66,12 +66,6 @@ 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 HashTable* on VM stack */
|
||||
if (opline->opcode == ZEND_OP_DATA &&
|
||||
(opline-1)->opcode == ZEND_FE_FETCH_RW &&
|
||||
opline->op1_type == IS_TMP_VAR) {
|
||||
start_of_T[VAR_NUM(ZEND_OP1(opline).var) - offset] = opline;
|
||||
}
|
||||
opline--;
|
||||
}
|
||||
|
||||
@@ -84,21 +78,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_RW &&
|
||||
opline->op1_type == IS_TMP_VAR) {
|
||||
max++;
|
||||
ZEND_OP1(opline).var = NUM_VAR(max + offset);
|
||||
} 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 */
|
||||
|
||||
@@ -203,7 +203,9 @@ void zend_optimizer_pass2(zend_op_array *op_array)
|
||||
jmp_to = &op_array->brk_cont_array[array_offset];
|
||||
array_offset = jmp_to->parent;
|
||||
if (--nest_levels > 0) {
|
||||
if (op_array->opcodes[jmp_to->brk].opcode == ZEND_FREE) {
|
||||
if (op_array->opcodes[jmp_to->brk].opcode == ZEND_FREE ||
|
||||
op_array->opcodes[jmp_to->brk].opcode == ZEND_FE_FREE ||
|
||||
op_array->opcodes[jmp_to->brk].opcode == ZEND_END_SILENCE) {
|
||||
dont_optimize = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2203,6 +2203,9 @@ PHP_FUNCTION(array_shift)
|
||||
q->key = NULL;
|
||||
ZVAL_COPY_VALUE(&q->val, &p->val);
|
||||
ZVAL_UNDEF(&p->val);
|
||||
if (idx == Z_ARRVAL_P(stack)->nInternalPointer) {
|
||||
zend_hash_iterators_update(Z_ARRVAL_P(stack), k);
|
||||
}
|
||||
}
|
||||
k++;
|
||||
}
|
||||
@@ -2265,9 +2268,14 @@ PHP_FUNCTION(array_unshift)
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
new_hash.nInternalPointer = Z_ARRVAL_P(stack)->nInternalPointer;
|
||||
new_hash.u.v.nIteratorsCount = Z_ARRVAL_P(stack)->u.v.nIteratorsCount;
|
||||
Z_ARRVAL_P(stack)->u.v.nIteratorsCount = 0;
|
||||
Z_ARRVAL_P(stack)->pDestructor = NULL;
|
||||
zend_hash_destroy(Z_ARRVAL_P(stack));
|
||||
*Z_ARRVAL_P(stack) = new_hash;
|
||||
zend_hash_iterators_update(Z_ARRVAL_P(stack), 0);
|
||||
zend_hash_internal_pointer_reset(Z_ARRVAL_P(stack));
|
||||
|
||||
/* Clean up and return the number of elements in the stack */
|
||||
RETVAL_LONG(zend_hash_num_elements(Z_ARRVAL_P(stack)));
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
--TEST--
|
||||
Directly modifying an unreferenced array when foreach'ing over it while using &$value syntax.
|
||||
--XFAIL--
|
||||
Needs major foreach changes to get sane behavior
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
@@ -70,7 +68,7 @@ withRefValue(3, $transform);
|
||||
withRefValue(4, $transform);
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
--EXPECT--
|
||||
|
||||
Popping elements off end of an unreferenced array, using &$value.
|
||||
---( Array with 1 element(s): )---
|
||||
@@ -95,9 +93,10 @@ array(2) {
|
||||
}
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=0; $v=v.0
|
||||
--> State of array after loop:
|
||||
array(0) {
|
||||
array(1) {
|
||||
[0]=>
|
||||
&string(3) "v.0"
|
||||
}
|
||||
|
||||
---( Array with 3 element(s): )---
|
||||
@@ -134,10 +133,12 @@ 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
|
||||
--> State of array after loop:
|
||||
array(0) {
|
||||
array(2) {
|
||||
[0]=>
|
||||
string(3) "v.0"
|
||||
[1]=>
|
||||
&string(3) "v.1"
|
||||
}
|
||||
|
||||
|
||||
@@ -289,12 +290,28 @@ array(1) {
|
||||
}
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=1; $v=new.0
|
||||
iteration 2: $k=2; $v=new.1
|
||||
iteration 3: $k=3; $v=new.2
|
||||
iteration 4: $k=4; $v=new.3
|
||||
iteration 5: $k=5; $v=new.4
|
||||
** Stuck in a loop! **
|
||||
--> State of array after loop:
|
||||
array(2) {
|
||||
array(7) {
|
||||
[0]=>
|
||||
&string(3) "v.0"
|
||||
string(3) "v.0"
|
||||
[1]=>
|
||||
string(5) "new.0"
|
||||
[2]=>
|
||||
string(5) "new.1"
|
||||
[3]=>
|
||||
string(5) "new.2"
|
||||
[4]=>
|
||||
string(5) "new.3"
|
||||
[5]=>
|
||||
&string(5) "new.4"
|
||||
[6]=>
|
||||
string(5) "new.5"
|
||||
}
|
||||
|
||||
---( Array with 2 element(s): )---
|
||||
@@ -428,12 +445,28 @@ array(1) {
|
||||
}
|
||||
--> 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! **
|
||||
--> State of array after loop:
|
||||
array(2) {
|
||||
array(7) {
|
||||
[0]=>
|
||||
string(5) "new.0"
|
||||
string(5) "new.5"
|
||||
[1]=>
|
||||
&string(3) "v.0"
|
||||
&string(5) "new.4"
|
||||
[2]=>
|
||||
string(5) "new.3"
|
||||
[3]=>
|
||||
string(5) "new.2"
|
||||
[4]=>
|
||||
string(5) "new.1"
|
||||
[5]=>
|
||||
string(5) "new.0"
|
||||
[6]=>
|
||||
string(3) "v.0"
|
||||
}
|
||||
|
||||
---( Array with 2 element(s): )---
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
--TEST--
|
||||
Directly modifying a REFERENCED array when foreach'ing over it while using &$value syntax.
|
||||
--XFAIL--
|
||||
Needs major foreach changes to get sane behavior
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
@@ -72,7 +70,7 @@ withRefValue(3, $transform);
|
||||
withRefValue(4, $transform);
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
--EXPECT--
|
||||
|
||||
Popping elements off end of a referenced array, using &$value
|
||||
---( Array with 1 element(s): )---
|
||||
@@ -97,9 +95,10 @@ array(2) {
|
||||
}
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=0; $v=v.0
|
||||
--> State of array after loop:
|
||||
array(0) {
|
||||
array(1) {
|
||||
[0]=>
|
||||
&string(3) "v.0"
|
||||
}
|
||||
|
||||
---( Array with 3 element(s): )---
|
||||
@@ -136,10 +135,12 @@ 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
|
||||
--> State of array after loop:
|
||||
array(0) {
|
||||
array(2) {
|
||||
[0]=>
|
||||
string(3) "v.0"
|
||||
[1]=>
|
||||
&string(3) "v.1"
|
||||
}
|
||||
|
||||
|
||||
@@ -291,12 +292,28 @@ array(1) {
|
||||
}
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=1; $v=new.0
|
||||
iteration 2: $k=2; $v=new.1
|
||||
iteration 3: $k=3; $v=new.2
|
||||
iteration 4: $k=4; $v=new.3
|
||||
iteration 5: $k=5; $v=new.4
|
||||
** Stuck in a loop! **
|
||||
--> State of array after loop:
|
||||
array(2) {
|
||||
array(7) {
|
||||
[0]=>
|
||||
&string(3) "v.0"
|
||||
string(3) "v.0"
|
||||
[1]=>
|
||||
string(5) "new.0"
|
||||
[2]=>
|
||||
string(5) "new.1"
|
||||
[3]=>
|
||||
string(5) "new.2"
|
||||
[4]=>
|
||||
string(5) "new.3"
|
||||
[5]=>
|
||||
&string(5) "new.4"
|
||||
[6]=>
|
||||
string(5) "new.5"
|
||||
}
|
||||
|
||||
---( Array with 2 element(s): )---
|
||||
@@ -430,12 +447,28 @@ array(1) {
|
||||
}
|
||||
--> 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! **
|
||||
--> State of array after loop:
|
||||
array(2) {
|
||||
array(7) {
|
||||
[0]=>
|
||||
string(5) "new.0"
|
||||
string(5) "new.5"
|
||||
[1]=>
|
||||
&string(3) "v.0"
|
||||
&string(5) "new.4"
|
||||
[2]=>
|
||||
string(5) "new.3"
|
||||
[3]=>
|
||||
string(5) "new.2"
|
||||
[4]=>
|
||||
string(5) "new.1"
|
||||
[5]=>
|
||||
string(5) "new.0"
|
||||
[6]=>
|
||||
string(3) "v.0"
|
||||
}
|
||||
|
||||
---( Array with 2 element(s): )---
|
||||
|
||||
Reference in New Issue
Block a user