]> granicus.if.org Git - php/commitdiff
Merged FE_FETCH_R[W] with the following ASSIGN[_REF] when assigne to CV.
authorDmitry Stogov <dmitry@zend.com>
Wed, 13 May 2015 09:55:42 +0000 (12:55 +0300)
committerDmitry Stogov <dmitry@zend.com>
Wed, 13 May 2015 09:55:42 +0000 (12:55 +0300)
Zend/zend_compile.c
Zend/zend_execute.c
Zend/zend_opcode.c
Zend/zend_types.h
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
ext/opcache/Optimizer/block_pass.c
ext/opcache/Optimizer/nop_removal.c
ext/opcache/Optimizer/zend_optimizer.c
ext/opcache/zend_file_cache.c
ext/opcache/zend_persist.c

index 2606304afbdd47883a2fffff52e89991075dc9f3..78f8ae3207b36e0bb90d11a08f1e545d3ac6ebcd 100644 (file)
@@ -3757,24 +3757,25 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */
        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, by_ref ? ZEND_FE_FETCH_RW : ZEND_FE_FETCH_R, &reset_node, NULL);
-       if (key_ast) {
-               opline->extended_value = 1;
-       }
-
-       opline = zend_emit_op(NULL, ZEND_OP_DATA, NULL, NULL);
-
-       if (key_ast) {
-               zend_make_tmp_result(&key_node, opline);
-       }
+       opline = zend_emit_op(NULL, by_ref ? ZEND_FE_FETCH_RW : ZEND_FE_FETCH_R, &reset_node, NULL);
 
-       if (by_ref) {
-               zend_emit_assign_ref_znode(value_ast, &value_node);
+       if (value_ast->kind == ZEND_AST_VAR &&
+           zend_try_compile_cv(&value_node, value_ast) == SUCCESS) {
+               SET_NODE(opline->op2, &value_node);
        } else {
-               zend_emit_assign_znode(value_ast, &value_node);
+               opline->op2_type = IS_VAR;
+               opline->op2.var = get_temporary_variable(CG(active_op_array));
+               GET_NODE(&value_node, opline->op2);
+               if (by_ref) {
+                       zend_emit_assign_ref_znode(value_ast, &value_node);
+               } else {
+                       zend_emit_assign_znode(value_ast, &value_node);
+               }
        }
 
        if (key_ast) {
+               opline = &CG(active_op_array)->opcodes[opnum_fetch];
+               zend_make_tmp_result(&key_node, opline);
                zend_emit_assign_znode(key_ast, &key_node);
        }
 
@@ -3788,7 +3789,7 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */
        opline->op2.opline_num = get_next_op_number(CG(active_op_array));
 
        opline = &CG(active_op_array)->opcodes[opnum_fetch];
-       opline->op2.opline_num = get_next_op_number(CG(active_op_array));
+       opline->extended_value = get_next_op_number(CG(active_op_array));
 
        zend_end_loop(opnum_fetch, 1);
 
index f523b279bbe7b583d1c6ead87478179938d82851..d29014d3b2fa84f6a9f641f695c62fa903aea1bb 100644 (file)
@@ -527,17 +527,18 @@ static inline zval *_get_obj_zval_ptr_ptr(int op_type, znode_op node, zend_execu
 
 static inline void zend_assign_to_variable_reference(zval *variable_ptr, zval *value_ptr)
 {
+       zend_reference *ref;
+
        if (EXPECTED(!Z_ISREF_P(value_ptr))) {
                ZVAL_NEW_REF(value_ptr, value_ptr);
+       } else if (UNEXPECTED(variable_ptr == value_ptr)) {
+               return;
        }
-       if (EXPECTED(variable_ptr != value_ptr)) {
-               zend_reference *ref;
 
-               ref = Z_REF_P(value_ptr);
-               GC_REFCOUNT(ref)++;
-               zval_ptr_dtor(variable_ptr);
-               ZVAL_REF(variable_ptr, ref);
-       }
+       ref = Z_REF_P(value_ptr);
+       GC_REFCOUNT(ref)++;
+       zval_ptr_dtor(variable_ptr);
+       ZVAL_REF(variable_ptr, ref);
 }
 
 /* this should modify object only if it's empty */
index 43ba64ad3fd44ad9b803d6665bd65475ab42db0b..f24fc9f1932657b5211f983f154b7c8b1bfbc877 100644 (file)
@@ -797,11 +797,13 @@ ZEND_API int pass_two(zend_op_array *op_array)
                        case ZEND_NEW:
                        case ZEND_FE_RESET_R:
                        case ZEND_FE_RESET_RW:
-                       case ZEND_FE_FETCH_R:
-                       case ZEND_FE_FETCH_RW:
                        case ZEND_ASSERT_CHECK:
                                ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op2);
                                break;
+                       case ZEND_FE_FETCH_R:
+                       case ZEND_FE_FETCH_RW:
+                               opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, opline->extended_value);
+                               break;
                        case ZEND_VERIFY_RETURN_TYPE:
                                if (op_array->fn_flags & ZEND_ACC_GENERATOR) {
                                        MAKE_NOP(opline);
index a7d8d9961175aa83b149b210eb9ecbc2be090f2d..d66da1eade513461f763d37b7c4964208376a693 100644 (file)
@@ -349,6 +349,8 @@ static zend_always_inline zend_uchar zval_get_type(const zval* pz) {
 #define Z_COUNTED(zval)                                (zval).value.counted
 #define Z_COUNTED_P(zval_p)                    Z_COUNTED(*(zval_p))
 
+#define Z_TYPE_MASK                                    0xff
+
 #define Z_TYPE_FLAGS_SHIFT                     8
 #define Z_CONST_FLAGS_SHIFT                    16
 
@@ -457,7 +459,7 @@ static zend_always_inline zend_uchar zval_get_type(const zval* pz) {
 #define Z_SYMBOLTABLE_P(zval_p)                Z_SYMBOLTABLE(*(zval_p))
 
 /* the following Z_OPT_* macros make better code when Z_TYPE_INFO accessed before */
-#define Z_OPT_TYPE(zval)                       (Z_TYPE_INFO(zval) & 0xff)
+#define Z_OPT_TYPE(zval)                       (Z_TYPE_INFO(zval) & Z_TYPE_MASK)
 #define Z_OPT_TYPE_P(zval_p)           Z_OPT_TYPE(*(zval_p))
 
 #define Z_OPT_CONSTANT(zval)           ((Z_TYPE_INFO(zval) & (IS_TYPE_CONSTANT << Z_TYPE_FLAGS_SHIFT)) != 0)
@@ -803,20 +805,15 @@ static zend_always_inline uint32_t zval_delref_p(zval* pz) {
 #if SIZEOF_ZEND_LONG == 4
 # define ZVAL_COPY_VALUE_EX(z, v, gc, t)                               \
        do {                                                                                            \
-               uint32_t _w2;                                                                   \
-               gc = v->value.counted;                                                  \
-               _w2 = v->value.ww.w2;                                                   \
-               t = Z_TYPE_INFO_P(v);                                                   \
-               z->value.counted = gc;                                                  \
+               uint32_t _w2 = v->value.ww.w2;                                  \
+               Z_COUNTED_P(z) = gc;                                                    \
                z->value.ww.w2 = _w2;                                                   \
                Z_TYPE_INFO_P(z) = t;                                                   \
        } while (0)
 #elif SIZEOF_ZEND_LONG == 8
 # define ZVAL_COPY_VALUE_EX(z, v, gc, t)                               \
        do {                                                                                            \
-               gc = v->value.counted;                                                  \
-               t = Z_TYPE_INFO_P(v);                                                   \
-               z->value.counted = gc;                                                  \
+               Z_COUNTED_P(z) = gc;                                                    \
                Z_TYPE_INFO_P(z) = t;                                                   \
        } while (0)
 #else
@@ -827,8 +824,8 @@ static zend_always_inline uint32_t zval_delref_p(zval* pz) {
        do {                                                                                            \
                zval *_z1 = (z);                                                                \
                const zval *_z2 = (v);                                                  \
-               zend_refcounted *_gc;                                                   \
-               uint32_t _t;                                                                    \
+               zend_refcounted *_gc = Z_COUNTED_P(_z2);                \
+               uint32_t _t = Z_TYPE_INFO_P(_z2);                               \
                ZVAL_COPY_VALUE_EX(_z1, _z2, _gc, _t);                  \
        } while (0)
 
@@ -836,8 +833,8 @@ static zend_always_inline uint32_t zval_delref_p(zval* pz) {
        do {                                                                                            \
                zval *_z1 = (z);                                                                \
                const zval *_z2 = (v);                                                  \
-               zend_refcounted *_gc;                                                   \
-               uint32_t _t;                                                                    \
+               zend_refcounted *_gc = Z_COUNTED_P(_z2);                \
+               uint32_t _t = Z_TYPE_INFO_P(_z2);                               \
                ZVAL_COPY_VALUE_EX(_z1, _z2, _gc, _t);                  \
                if ((_t & (IS_TYPE_REFCOUNTED << Z_TYPE_FLAGS_SHIFT)) != 0) { \
                        GC_REFCOUNT(_gc)++;                                                     \
@@ -848,8 +845,8 @@ static zend_always_inline uint32_t zval_delref_p(zval* pz) {
        do {                                                                                            \
                zval *_z1 = (z);                                                                \
                const zval *_z2 = (v);                                                  \
-               zend_refcounted *_gc;                                                   \
-               uint32_t _t;                                                                    \
+               zend_refcounted *_gc = Z_COUNTED_P(_z2);                \
+               uint32_t _t = Z_TYPE_INFO_P(_z2);                               \
                ZVAL_COPY_VALUE_EX(_z1, _z2, _gc, _t);                  \
                if ((_t & ((IS_TYPE_REFCOUNTED|IS_TYPE_IMMUTABLE) << Z_TYPE_FLAGS_SHIFT)) != 0) { \
                        if ((_t & ((IS_TYPE_COPYABLE|IS_TYPE_IMMUTABLE) << Z_TYPE_FLAGS_SHIFT)) != 0) { \
index eec2891ad70897565b44f63e753fd538c3cf0d6c..facc1f8696109082153cc473bbd2543305bab62e 100644 (file)
@@ -6010,6 +6010,7 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH_R, VAR, ANY)
        USE_OPLINE
        zval *array;
        zval *value;
+       uint32_t value_type;
        HashTable *fe_ht;
        HashPosition pos;
        Bucket *p;
@@ -6018,21 +6019,23 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH_R, VAR, ANY)
        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));
+               pos = Z_FE_POS_P(array);
                p = fe_ht->arData + pos;
                while (1) {
                        if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
                                /* reached end of iteration */
-                               ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+                               ZEND_VM_C_GOTO(fe_fetch_r_exit);
                        }
                        value = &p->val;
-                       if (Z_TYPE_INFO_P(value) == IS_UNDEF) {
+                       value_type = Z_TYPE_INFO_P(value);
+                       if (value_type == IS_UNDEF) {
                                pos++;
                                p++;
                                continue;
-                       } else if (UNEXPECTED(Z_TYPE_INFO_P(value) == IS_INDIRECT)) {
+                       } else if (UNEXPECTED(value_type == IS_INDIRECT)) {
                                value = Z_INDIRECT_P(value);
-                               if (UNEXPECTED(Z_TYPE_INFO_P(value) == IS_UNDEF)) {
+                               value_type = Z_TYPE_INFO_P(value);
+                               if (UNEXPECTED(value_type == IS_UNDEF)) {
                                        pos++;
                                        p++;
                                        continue;
@@ -6040,17 +6043,14 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH_R, VAR, ANY)
                        }
                        break;
                }
-               ZVAL_COPY(EX_VAR(opline->result.var), value);
-               Z_FE_POS_P(EX_VAR(opline->op1.var)) = pos + 1;
-               if (opline->extended_value) {
+               Z_FE_POS_P(array) = pos + 1;
+               if (opline->result_type == IS_TMP_VAR) {
                        if (!p->key) {
-                               ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
+                               ZVAL_LONG(EX_VAR(opline->result.var), p->h);
                        } else {
-                               ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
+                               ZVAL_STR_COPY(EX_VAR(opline->result.var), p->key);
                        }
                }
-               ZEND_VM_INC_OPCODE();
-               ZEND_VM_NEXT_OPCODE();
        } else if (EXPECTED(Z_TYPE_P(array) == IS_OBJECT)) {
                zend_object_iterator *iter;
 
@@ -6058,22 +6058,24 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH_R, VAR, ANY)
                        /* plain object */
 
                        fe_ht = Z_OBJPROP_P(array);
-                       pos = zend_hash_iterator_pos(Z_FE_ITER_P(EX_VAR(opline->op1.var)), fe_ht);
+                       pos = zend_hash_iterator_pos(Z_FE_ITER_P(array), fe_ht);
                        p = fe_ht->arData + pos;
                        while (1) {
                                if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
                                        /* reached end of iteration */
-                                       ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+                                       ZEND_VM_C_GOTO(fe_fetch_r_exit);
                                }
 
                                value = &p->val;
-                               if (UNEXPECTED(Z_TYPE_INFO_P(value) == IS_UNDEF)) {
+                               value_type = Z_TYPE_INFO_P(value);
+                               if (UNEXPECTED(value_type == IS_UNDEF)) {
                                        pos++;
                                        p++;
                                        continue;
-                               } else if (UNEXPECTED(Z_TYPE_INFO_P(value) == IS_INDIRECT)) {
+                               } else if (UNEXPECTED(value_type == IS_INDIRECT)) {
                                        value = Z_INDIRECT_P(value);
-                                       if (UNEXPECTED(Z_TYPE_INFO_P(value) == IS_UNDEF)) {
+                                       value_type = Z_TYPE_INFO_P(value);
+                                       if (UNEXPECTED(value_type == IS_UNDEF)) {
                                                pos++;
                                                p++;
                                                continue;
@@ -6086,18 +6088,17 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH_R, VAR, ANY)
                                pos++;
                                p++;
                        }
-                       ZVAL_COPY(EX_VAR(opline->result.var), value);
-                       if (opline->extended_value) {
+                       if (opline->result_type == IS_TMP_VAR) {
                                if (UNEXPECTED(!p->key)) {
-                                       ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
+                                       ZVAL_LONG(EX_VAR(opline->result.var), p->h);
                                } else if (p->key->val[0]) {
-                                       ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
+                                       ZVAL_STR_COPY(EX_VAR(opline->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_STRINGL(EX_VAR(opline->result.var), prop_name, prop_name_len);
                                }
                        }
                        while (1) {
@@ -6115,12 +6116,9 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH_R, VAR, ANY)
                                        break;
                                }
                        }
-                       EG(ht_iterators)[Z_FE_ITER_P(EX_VAR(opline->op1.var))].pos = pos;
-                       ZEND_VM_INC_OPCODE();
-                       ZEND_VM_NEXT_OPCODE();
+                       EG(ht_iterators)[Z_FE_ITER_P(array)].pos = pos;
                } else {
-                       /* !iter happens from exception */
-                       if (iter && ++iter->index > 0) {
+                       if (EXPECTED(++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);
@@ -6128,15 +6126,14 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH_R, VAR, ANY)
                                        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();
+                               if (UNEXPECTED(iter->funcs->valid(iter) == FAILURE)) {
+                                       /* reached end of iteration */
+                                       if (UNEXPECTED(EG(exception) != NULL)) {
+                                               zval_ptr_dtor(array);
+                                               HANDLE_EXCEPTION();
+                                       }
+                                       ZEND_VM_C_GOTO(fe_fetch_r_exit);
                                }
-                               ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
                        }
                        value = iter->funcs->get_current_data(iter);
                        if (UNEXPECTED(EG(exception) != NULL)) {
@@ -6145,27 +6142,43 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH_R, VAR, ANY)
                        }
                        if (!value) {
                                /* failure in get_current_data */
-                               ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+                               ZEND_VM_C_GOTO(fe_fetch_r_exit);
                        }
-                       ZVAL_COPY(EX_VAR(opline->result.var), value);
-                       if (opline->extended_value) {
+                       if (opline->result_type == IS_TMP_VAR) {
                                if (iter->funcs->get_current_key) {
-                                       iter->funcs->get_current_key(iter, EX_VAR((opline+1)->result.var));
+                                       iter->funcs->get_current_key(iter, EX_VAR(opline->result.var));
                                        if (UNEXPECTED(EG(exception) != NULL)) {
                                                zval_ptr_dtor(array);
                                                HANDLE_EXCEPTION();
                                        }
                                } else {
-                                       ZVAL_LONG(EX_VAR((opline+1)->result.var), iter->index);
+                                       ZVAL_LONG(EX_VAR(opline->result.var), iter->index);
                                }
                        }
-                       ZEND_VM_INC_OPCODE();
-                       ZEND_VM_NEXT_OPCODE();
+                       value_type = Z_TYPE_INFO_P(value);
                }
        } else {
                zend_error(E_WARNING, "Invalid argument supplied for foreach()");
-               ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+ZEND_VM_C_LABEL(fe_fetch_r_exit):
+               if (EXPECTED(!EG(exception))) {
+                       ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
+               }
+               ZEND_VM_CONTINUE();
        }
+
+       if (EXPECTED(OP2_TYPE == IS_CV)) {
+               zval *variable_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->op2.var);
+               zend_assign_to_variable(variable_ptr, value, IS_CV);
+       } else {
+               zval *res = EX_VAR(opline->op2.var);
+               zend_refcounted *gc = Z_COUNTED_P(value);
+
+               ZVAL_COPY_VALUE_EX(res, value, gc, value_type);
+               if (EXPECTED((value_type & (IS_TYPE_REFCOUNTED << Z_TYPE_FLAGS_SHIFT)) != 0)) {
+                       GC_REFCOUNT(gc)++;
+               }
+       }
+       ZEND_VM_NEXT_OPCODE();
 }
 
 ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY)
@@ -6173,6 +6186,7 @@ ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY)
        USE_OPLINE
        zval *array;
        zval *value;
+       uint32_t value_type;
        HashTable *fe_ht;
        HashPosition pos;
        Bucket *p;
@@ -6188,16 +6202,18 @@ ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY)
                while (1) {
                        if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
                                /* reached end of iteration */
-                               ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+                               ZEND_VM_C_GOTO(fe_fetch_w_exit);
                        }
                        value = &p->val;
-                       if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
+                       value_type = Z_TYPE_INFO_P(value);
+                       if (UNEXPECTED(value_type == IS_UNDEF)) {
                                pos++;
                                p++;
                                continue;
-                       } else if (UNEXPECTED(Z_TYPE_P(value) == IS_INDIRECT)) {
+                       } else if (UNEXPECTED(value_type == IS_INDIRECT)) {
                                value = Z_INDIRECT_P(value);
-                               if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
+                               value_type = Z_TYPE_INFO_P(value);
+                               if (UNEXPECTED(value_type == IS_UNDEF)) {
                                        pos++;
                                        p++;
                                        continue;
@@ -6205,14 +6221,11 @@ ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY)
                        }
                        break;
                }
-               ZVAL_MAKE_REF(value);
-               Z_ADDREF_P(value);
-               ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
-               if (opline->extended_value) {
+               if (opline->result_type == IS_TMP_VAR) {
                        if (!p->key) {
-                               ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
+                               ZVAL_LONG(EX_VAR(opline->result.var), p->h);
                        } else {
-                               ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
+                               ZVAL_STR_COPY(EX_VAR(opline->result.var), p->key);
                        }
                }
                while (1) {
@@ -6229,8 +6242,6 @@ ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY)
                        }
                }
                EG(ht_iterators)[Z_FE_ITER_P(EX_VAR(opline->op1.var))].pos = pos;
-               ZEND_VM_INC_OPCODE();
-               ZEND_VM_NEXT_OPCODE();
        } else if (EXPECTED(Z_TYPE_P(array) == IS_OBJECT)) {
                zend_object_iterator *iter;
 
@@ -6243,17 +6254,19 @@ ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY)
                        while (1) {
                                if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
                                        /* reached end of iteration */
-                                       ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+                                       ZEND_VM_C_GOTO(fe_fetch_w_exit);
                                }
 
                                value = &p->val;
-                               if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
+                               value_type = Z_TYPE_INFO_P(value);
+                               if (UNEXPECTED(value_type == IS_UNDEF)) {
                                        pos++;
                                        p++;
                                        continue;
-                               } else if (UNEXPECTED(Z_TYPE_P(value) == IS_INDIRECT)) {
+                               } else if (UNEXPECTED(value_type == IS_INDIRECT)) {
                                        value = Z_INDIRECT_P(value);
-                                       if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
+                                       value_type = Z_TYPE_INFO_P(value);
+                                       if (UNEXPECTED(value_type == IS_UNDEF)) {
                                                pos++;
                                                p++;
                                                continue;
@@ -6266,20 +6279,17 @@ ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY)
                                pos++;
                                p++;
                        }
-                       ZVAL_MAKE_REF(value);
-                       Z_ADDREF_P(value);
-                       ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
-                       if (opline->extended_value) {
+                       if (opline->result_type == IS_TMP_VAR) {
                                if (UNEXPECTED(!p->key)) {
-                                       ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
+                                       ZVAL_LONG(EX_VAR(opline->result.var), p->h);
                                } else if (p->key->val[0]) {
-                                       ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
+                                       ZVAL_STR_COPY(EX_VAR(opline->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_STRINGL(EX_VAR(opline->result.var), prop_name, prop_name_len);
                                }
                        }
                        while (1) {
@@ -6298,11 +6308,8 @@ ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY)
                                }
                        }
                        EG(ht_iterators)[Z_FE_ITER_P(EX_VAR(opline->op1.var))].pos = pos;
-                       ZEND_VM_INC_OPCODE();
-                       ZEND_VM_NEXT_OPCODE();
                } else {
-                       /* !iter happens from exception */
-                       if (iter && ++iter->index > 0) {
+                       if (++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);
@@ -6310,15 +6317,14 @@ ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY)
                                        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();
+                               if (UNEXPECTED(iter->funcs->valid(iter) == FAILURE)) {
+                                       /* reached end of iteration */
+                                       if (UNEXPECTED(EG(exception) != NULL)) {
+                                               zval_ptr_dtor(array);
+                                               HANDLE_EXCEPTION();
+                                       }
+                                       ZEND_VM_C_GOTO(fe_fetch_w_exit);
                                }
-                               ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
                        }
                        value = iter->funcs->get_current_data(iter);
                        if (UNEXPECTED(EG(exception) != NULL)) {
@@ -6327,29 +6333,52 @@ ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY)
                        }
                        if (!value) {
                                /* failure in get_current_data */
-                               ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+                               ZEND_VM_C_GOTO(fe_fetch_w_exit);
                        }
-                       if (opline->extended_value) {
+                       if (opline->result_type == IS_TMP_VAR) {
                                if (iter->funcs->get_current_key) {
-                                       iter->funcs->get_current_key(iter, EX_VAR((opline+1)->result.var));
+                                       iter->funcs->get_current_key(iter, EX_VAR(opline->result.var));
                                        if (UNEXPECTED(EG(exception) != NULL)) {
                                                zval_ptr_dtor(array);
                                                HANDLE_EXCEPTION();
                                        }
                                } else {
-                                       ZVAL_LONG(EX_VAR((opline+1)->result.var), iter->index);
+                                       ZVAL_LONG(EX_VAR(opline->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();
+                       value_type = Z_TYPE_INFO_P(value);
                }
        } else {
                zend_error(E_WARNING, "Invalid argument supplied for foreach()");
-               ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+ZEND_VM_C_LABEL(fe_fetch_w_exit):
+               if (EXPECTED(!EG(exception))) {
+                       ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
+               }
+               ZEND_VM_CONTINUE();
+       }
+
+       if (EXPECTED((value_type & Z_TYPE_MASK) != IS_REFERENCE)) {
+               zend_refcounted *gc = Z_COUNTED_P(value);
+               zval *ref;
+               ZVAL_NEW_EMPTY_REF(value);
+               ref = Z_REFVAL_P(value);
+               ZVAL_COPY_VALUE_EX(ref, value, gc, value_type);
        }
+       if (EXPECTED(OP2_TYPE == IS_CV)) {
+               zval *variable_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->op2.var);
+               if (EXPECTED(variable_ptr != value)) {
+                       zend_reference *ref;
+
+                       ref = Z_REF_P(value);
+                       GC_REFCOUNT(ref)++;
+                       zval_ptr_dtor(variable_ptr);
+                       ZVAL_REF(variable_ptr, ref);
+               }
+       } else {
+               Z_ADDREF_P(value);
+               ZVAL_REF(EX_VAR(opline->op2.var), Z_REF_P(value));
+       }
+       ZEND_VM_NEXT_OPCODE();
 }
 
 ZEND_VM_HANDLER(114, ZEND_ISSET_ISEMPTY_VAR, CONST|TMPVAR|CV, UNUSED|CONST|VAR)
@@ -7766,12 +7795,14 @@ ZEND_VM_C_LABEL(check_indirect):
 
        variable_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W);
 
-       if (UNEXPECTED(!Z_ISREF_P(value))) {
-               ZVAL_NEW_REF(value, value);
-       }
-       if (EXPECTED(variable_ptr != value)) {
+       do {
                zend_reference *ref;
 
+               if (UNEXPECTED(!Z_ISREF_P(value))) {
+                       ZVAL_NEW_REF(value, value);
+               } else if (UNEXPECTED(variable_ptr == value)) {
+                       break;
+               }
                ref = Z_REF_P(value);
                GC_REFCOUNT(ref)++;
                if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr))) {
@@ -7787,7 +7818,7 @@ ZEND_VM_C_LABEL(check_indirect):
                        }
                }
                ZVAL_REF(variable_ptr, ref);
-       }
+       } while (0);
 
        ZEND_VM_REPEAT_OPCODE(ZEND_BIND_GLOBAL);
        ZEND_VM_NEXT_OPCODE();
index acb0151dd462a3b45e33b6e03639416185e08e04..d4902ef9729862ecd8bc0035fd743d1ff01548e2 100644 (file)
@@ -15653,6 +15653,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FETCH_R_SPEC_VAR_HANDLER(ZE
        USE_OPLINE
        zval *array;
        zval *value;
+       uint32_t value_type;
        HashTable *fe_ht;
        HashPosition pos;
        Bucket *p;
@@ -15661,21 +15662,23 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FETCH_R_SPEC_VAR_HANDLER(ZE
        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));
+               pos = Z_FE_POS_P(array);
                p = fe_ht->arData + pos;
                while (1) {
                        if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
                                /* reached end of iteration */
-                               ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+                               goto fe_fetch_r_exit;
                        }
                        value = &p->val;
-                       if (Z_TYPE_INFO_P(value) == IS_UNDEF) {
+                       value_type = Z_TYPE_INFO_P(value);
+                       if (value_type == IS_UNDEF) {
                                pos++;
                                p++;
                                continue;
-                       } else if (UNEXPECTED(Z_TYPE_INFO_P(value) == IS_INDIRECT)) {
+                       } else if (UNEXPECTED(value_type == IS_INDIRECT)) {
                                value = Z_INDIRECT_P(value);
-                               if (UNEXPECTED(Z_TYPE_INFO_P(value) == IS_UNDEF)) {
+                               value_type = Z_TYPE_INFO_P(value);
+                               if (UNEXPECTED(value_type == IS_UNDEF)) {
                                        pos++;
                                        p++;
                                        continue;
@@ -15683,17 +15686,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FETCH_R_SPEC_VAR_HANDLER(ZE
                        }
                        break;
                }
-               ZVAL_COPY(EX_VAR(opline->result.var), value);
-               Z_FE_POS_P(EX_VAR(opline->op1.var)) = pos + 1;
-               if (opline->extended_value) {
+               Z_FE_POS_P(array) = pos + 1;
+               if (opline->result_type == IS_TMP_VAR) {
                        if (!p->key) {
-                               ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
+                               ZVAL_LONG(EX_VAR(opline->result.var), p->h);
                        } else {
-                               ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
+                               ZVAL_STR_COPY(EX_VAR(opline->result.var), p->key);
                        }
                }
-               ZEND_VM_INC_OPCODE();
-               ZEND_VM_NEXT_OPCODE();
        } else if (EXPECTED(Z_TYPE_P(array) == IS_OBJECT)) {
                zend_object_iterator *iter;
 
@@ -15701,22 +15701,24 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FETCH_R_SPEC_VAR_HANDLER(ZE
                        /* plain object */
 
                        fe_ht = Z_OBJPROP_P(array);
-                       pos = zend_hash_iterator_pos(Z_FE_ITER_P(EX_VAR(opline->op1.var)), fe_ht);
+                       pos = zend_hash_iterator_pos(Z_FE_ITER_P(array), fe_ht);
                        p = fe_ht->arData + pos;
                        while (1) {
                                if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
                                        /* reached end of iteration */
-                                       ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+                                       goto fe_fetch_r_exit;
                                }
 
                                value = &p->val;
-                               if (UNEXPECTED(Z_TYPE_INFO_P(value) == IS_UNDEF)) {
+                               value_type = Z_TYPE_INFO_P(value);
+                               if (UNEXPECTED(value_type == IS_UNDEF)) {
                                        pos++;
                                        p++;
                                        continue;
-                               } else if (UNEXPECTED(Z_TYPE_INFO_P(value) == IS_INDIRECT)) {
+                               } else if (UNEXPECTED(value_type == IS_INDIRECT)) {
                                        value = Z_INDIRECT_P(value);
-                                       if (UNEXPECTED(Z_TYPE_INFO_P(value) == IS_UNDEF)) {
+                                       value_type = Z_TYPE_INFO_P(value);
+                                       if (UNEXPECTED(value_type == IS_UNDEF)) {
                                                pos++;
                                                p++;
                                                continue;
@@ -15729,18 +15731,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FETCH_R_SPEC_VAR_HANDLER(ZE
                                pos++;
                                p++;
                        }
-                       ZVAL_COPY(EX_VAR(opline->result.var), value);
-                       if (opline->extended_value) {
+                       if (opline->result_type == IS_TMP_VAR) {
                                if (UNEXPECTED(!p->key)) {
-                                       ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
+                                       ZVAL_LONG(EX_VAR(opline->result.var), p->h);
                                } else if (p->key->val[0]) {
-                                       ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
+                                       ZVAL_STR_COPY(EX_VAR(opline->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_STRINGL(EX_VAR(opline->result.var), prop_name, prop_name_len);
                                }
                        }
                        while (1) {
@@ -15758,12 +15759,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FETCH_R_SPEC_VAR_HANDLER(ZE
                                        break;
                                }
                        }
-                       EG(ht_iterators)[Z_FE_ITER_P(EX_VAR(opline->op1.var))].pos = pos;
-                       ZEND_VM_INC_OPCODE();
-                       ZEND_VM_NEXT_OPCODE();
+                       EG(ht_iterators)[Z_FE_ITER_P(array)].pos = pos;
                } else {
-                       /* !iter happens from exception */
-                       if (iter && ++iter->index > 0) {
+                       if (EXPECTED(++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);
@@ -15771,15 +15769,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FETCH_R_SPEC_VAR_HANDLER(ZE
                                        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();
+                               if (UNEXPECTED(iter->funcs->valid(iter) == FAILURE)) {
+                                       /* reached end of iteration */
+                                       if (UNEXPECTED(EG(exception) != NULL)) {
+                                               zval_ptr_dtor(array);
+                                               HANDLE_EXCEPTION();
+                                       }
+                                       goto fe_fetch_r_exit;
                                }
-                               ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
                        }
                        value = iter->funcs->get_current_data(iter);
                        if (UNEXPECTED(EG(exception) != NULL)) {
@@ -15788,27 +15785,43 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FETCH_R_SPEC_VAR_HANDLER(ZE
                        }
                        if (!value) {
                                /* failure in get_current_data */
-                               ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+                               goto fe_fetch_r_exit;
                        }
-                       ZVAL_COPY(EX_VAR(opline->result.var), value);
-                       if (opline->extended_value) {
+                       if (opline->result_type == IS_TMP_VAR) {
                                if (iter->funcs->get_current_key) {
-                                       iter->funcs->get_current_key(iter, EX_VAR((opline+1)->result.var));
+                                       iter->funcs->get_current_key(iter, EX_VAR(opline->result.var));
                                        if (UNEXPECTED(EG(exception) != NULL)) {
                                                zval_ptr_dtor(array);
                                                HANDLE_EXCEPTION();
                                        }
                                } else {
-                                       ZVAL_LONG(EX_VAR((opline+1)->result.var), iter->index);
+                                       ZVAL_LONG(EX_VAR(opline->result.var), iter->index);
                                }
                        }
-                       ZEND_VM_INC_OPCODE();
-                       ZEND_VM_NEXT_OPCODE();
+                       value_type = Z_TYPE_INFO_P(value);
                }
        } else {
                zend_error(E_WARNING, "Invalid argument supplied for foreach()");
-               ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+fe_fetch_r_exit:
+               if (EXPECTED(!EG(exception))) {
+                       ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
+               }
+               ZEND_VM_CONTINUE();
        }
+
+       if (EXPECTED(opline->op2_type == IS_CV)) {
+               zval *variable_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->op2.var);
+               zend_assign_to_variable(variable_ptr, value, IS_CV);
+       } else {
+               zval *res = EX_VAR(opline->op2.var);
+               zend_refcounted *gc = Z_COUNTED_P(value);
+
+               ZVAL_COPY_VALUE_EX(res, value, gc, value_type);
+               if (EXPECTED((value_type & (IS_TYPE_REFCOUNTED << Z_TYPE_FLAGS_SHIFT)) != 0)) {
+                       GC_REFCOUNT(gc)++;
+               }
+       }
+       ZEND_VM_NEXT_OPCODE();
 }
 
 static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
@@ -15816,6 +15829,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER(Z
        USE_OPLINE
        zval *array;
        zval *value;
+       uint32_t value_type;
        HashTable *fe_ht;
        HashPosition pos;
        Bucket *p;
@@ -15831,16 +15845,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER(Z
                while (1) {
                        if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
                                /* reached end of iteration */
-                               ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+                               goto fe_fetch_w_exit;
                        }
                        value = &p->val;
-                       if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
+                       value_type = Z_TYPE_INFO_P(value);
+                       if (UNEXPECTED(value_type == IS_UNDEF)) {
                                pos++;
                                p++;
                                continue;
-                       } else if (UNEXPECTED(Z_TYPE_P(value) == IS_INDIRECT)) {
+                       } else if (UNEXPECTED(value_type == IS_INDIRECT)) {
                                value = Z_INDIRECT_P(value);
-                               if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
+                               value_type = Z_TYPE_INFO_P(value);
+                               if (UNEXPECTED(value_type == IS_UNDEF)) {
                                        pos++;
                                        p++;
                                        continue;
@@ -15848,14 +15864,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER(Z
                        }
                        break;
                }
-               ZVAL_MAKE_REF(value);
-               Z_ADDREF_P(value);
-               ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
-               if (opline->extended_value) {
+               if (opline->result_type == IS_TMP_VAR) {
                        if (!p->key) {
-                               ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
+                               ZVAL_LONG(EX_VAR(opline->result.var), p->h);
                        } else {
-                               ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
+                               ZVAL_STR_COPY(EX_VAR(opline->result.var), p->key);
                        }
                }
                while (1) {
@@ -15872,8 +15885,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER(Z
                        }
                }
                EG(ht_iterators)[Z_FE_ITER_P(EX_VAR(opline->op1.var))].pos = pos;
-               ZEND_VM_INC_OPCODE();
-               ZEND_VM_NEXT_OPCODE();
        } else if (EXPECTED(Z_TYPE_P(array) == IS_OBJECT)) {
                zend_object_iterator *iter;
 
@@ -15886,17 +15897,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER(Z
                        while (1) {
                                if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
                                        /* reached end of iteration */
-                                       ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+                                       goto fe_fetch_w_exit;
                                }
 
                                value = &p->val;
-                               if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
+                               value_type = Z_TYPE_INFO_P(value);
+                               if (UNEXPECTED(value_type == IS_UNDEF)) {
                                        pos++;
                                        p++;
                                        continue;
-                               } else if (UNEXPECTED(Z_TYPE_P(value) == IS_INDIRECT)) {
+                               } else if (UNEXPECTED(value_type == IS_INDIRECT)) {
                                        value = Z_INDIRECT_P(value);
-                                       if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
+                                       value_type = Z_TYPE_INFO_P(value);
+                                       if (UNEXPECTED(value_type == IS_UNDEF)) {
                                                pos++;
                                                p++;
                                                continue;
@@ -15909,20 +15922,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER(Z
                                pos++;
                                p++;
                        }
-                       ZVAL_MAKE_REF(value);
-                       Z_ADDREF_P(value);
-                       ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
-                       if (opline->extended_value) {
+                       if (opline->result_type == IS_TMP_VAR) {
                                if (UNEXPECTED(!p->key)) {
-                                       ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
+                                       ZVAL_LONG(EX_VAR(opline->result.var), p->h);
                                } else if (p->key->val[0]) {
-                                       ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
+                                       ZVAL_STR_COPY(EX_VAR(opline->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_STRINGL(EX_VAR(opline->result.var), prop_name, prop_name_len);
                                }
                        }
                        while (1) {
@@ -15941,11 +15951,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER(Z
                                }
                        }
                        EG(ht_iterators)[Z_FE_ITER_P(EX_VAR(opline->op1.var))].pos = pos;
-                       ZEND_VM_INC_OPCODE();
-                       ZEND_VM_NEXT_OPCODE();
                } else {
-                       /* !iter happens from exception */
-                       if (iter && ++iter->index > 0) {
+                       if (++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);
@@ -15953,15 +15960,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER(Z
                                        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();
+                               if (UNEXPECTED(iter->funcs->valid(iter) == FAILURE)) {
+                                       /* reached end of iteration */
+                                       if (UNEXPECTED(EG(exception) != NULL)) {
+                                               zval_ptr_dtor(array);
+                                               HANDLE_EXCEPTION();
+                                       }
+                                       goto fe_fetch_w_exit;
                                }
-                               ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
                        }
                        value = iter->funcs->get_current_data(iter);
                        if (UNEXPECTED(EG(exception) != NULL)) {
@@ -15970,29 +15976,52 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER(Z
                        }
                        if (!value) {
                                /* failure in get_current_data */
-                               ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+                               goto fe_fetch_w_exit;
                        }
-                       if (opline->extended_value) {
+                       if (opline->result_type == IS_TMP_VAR) {
                                if (iter->funcs->get_current_key) {
-                                       iter->funcs->get_current_key(iter, EX_VAR((opline+1)->result.var));
+                                       iter->funcs->get_current_key(iter, EX_VAR(opline->result.var));
                                        if (UNEXPECTED(EG(exception) != NULL)) {
                                                zval_ptr_dtor(array);
                                                HANDLE_EXCEPTION();
                                        }
                                } else {
-                                       ZVAL_LONG(EX_VAR((opline+1)->result.var), iter->index);
+                                       ZVAL_LONG(EX_VAR(opline->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();
+                       value_type = Z_TYPE_INFO_P(value);
                }
        } else {
                zend_error(E_WARNING, "Invalid argument supplied for foreach()");
-               ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+fe_fetch_w_exit:
+               if (EXPECTED(!EG(exception))) {
+                       ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
+               }
+               ZEND_VM_CONTINUE();
+       }
+
+       if (EXPECTED((value_type & Z_TYPE_MASK) != IS_REFERENCE)) {
+               zend_refcounted *gc = Z_COUNTED_P(value);
+               zval *ref;
+               ZVAL_NEW_EMPTY_REF(value);
+               ref = Z_REFVAL_P(value);
+               ZVAL_COPY_VALUE_EX(ref, value, gc, value_type);
        }
+       if (EXPECTED(opline->op2_type == IS_CV)) {
+               zval *variable_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->op2.var);
+               if (EXPECTED(variable_ptr != value)) {
+                       zend_reference *ref;
+
+                       ref = Z_REF_P(value);
+                       GC_REFCOUNT(ref)++;
+                       zval_ptr_dtor(variable_ptr);
+                       ZVAL_REF(variable_ptr, ref);
+               }
+       } else {
+               Z_ADDREF_P(value);
+               ZVAL_REF(EX_VAR(opline->op2.var), Z_REF_P(value));
+       }
+       ZEND_VM_NEXT_OPCODE();
 }
 
 static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_JMP_SET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
@@ -33059,12 +33088,14 @@ check_indirect:
 
        variable_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->op1.var);
 
-       if (UNEXPECTED(!Z_ISREF_P(value))) {
-               ZVAL_NEW_REF(value, value);
-       }
-       if (EXPECTED(variable_ptr != value)) {
+       do {
                zend_reference *ref;
 
+               if (UNEXPECTED(!Z_ISREF_P(value))) {
+                       ZVAL_NEW_REF(value, value);
+               } else if (UNEXPECTED(variable_ptr == value)) {
+                       break;
+               }
                ref = Z_REF_P(value);
                GC_REFCOUNT(ref)++;
                if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr))) {
@@ -33080,7 +33111,7 @@ check_indirect:
                        }
                }
                ZVAL_REF(variable_ptr, ref);
-       }
+       } while (0);
 
        ZEND_VM_REPEAT_OPCODE(ZEND_BIND_GLOBAL);
        ZEND_VM_NEXT_OPCODE();
index a757d55fced7f1d769776631eb8a3df72084ade3..275e3f5fa250b482854c65cef014ffd670926e59 100644 (file)
@@ -179,8 +179,8 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimiz
                                break;
                        case ZEND_FE_FETCH_R:
                        case ZEND_FE_FETCH_RW:
-                               START_BLOCK_OP(ZEND_OP2(opline).opline_num);
-                               START_BLOCK_OP(opno + 2);
+                               START_BLOCK_OP(opline->extended_value);
+                               START_BLOCK_OP(opno + 1);
                                break;
                }
                opno++;
@@ -303,6 +303,11 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimiz
                                        cur_block->ext_to = &blocks[opline->extended_value];
                                        cur_block->follow_to = &blocks[opno];
                                        break;
+                               case ZEND_FE_FETCH_R:
+                               case ZEND_FE_FETCH_RW:
+                                       cur_block->ext_to = &blocks[opline->extended_value];
+                                       cur_block->follow_to = &blocks[opno];
+                                       break;
                                case ZEND_JMPZ:
                                case ZEND_JMPNZ:
                                case ZEND_JMPZ_EX:
@@ -312,8 +317,6 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimiz
                                case ZEND_NEW:
                                case ZEND_JMP_SET:
                                case ZEND_COALESCE:
-                               case ZEND_FE_FETCH_R:
-                               case ZEND_FE_FETCH_RW:
                                case ZEND_ASSERT_CHECK:
                                        cur_block->op2_to = &blocks[ZEND_OP2(opline).opline_num];
                                        /* break missing intentionally */
@@ -1774,7 +1777,14 @@ static void zend_t_usage(zend_code_block *block, zend_op_array *op_array, char *
 
                while (opline<end) {
                        T_USAGE(opline->op1);
-                       T_USAGE(opline->op2);
+                       if (opline->op2_type & (IS_VAR | IS_TMP_VAR)) {
+                               if (opline->opcode == ZEND_FE_FETCH_R || opline->opcode == ZEND_FE_FETCH_RW) {
+                                       /* these opcode use the op2 as result */
+                                       defined_here[VAR_NUM(ZEND_OP2(opline).var)] = 1;
+                               } else {
+                                       T_USAGE(opline->op2);
+                               }
+                       }
 
                        if (RESULT_USED(opline)) {
                                if (!defined_here[VAR_NUM(ZEND_RESULT(opline).var)] && !used_ext[VAR_NUM(ZEND_RESULT(opline).var)] &&
index 4a985df17c004567d72e6ca5abcfd9762d4db075..20510b416352da3a46479a1beac362348934a156 100644 (file)
@@ -95,8 +95,6 @@ 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_R:
-                               case ZEND_FE_FETCH_RW:
                                case ZEND_FE_RESET_R:
                                case ZEND_FE_RESET_RW:
                                case ZEND_NEW:
@@ -105,6 +103,10 @@ void zend_optimizer_nop_removal(zend_op_array *op_array)
                                case ZEND_ASSERT_CHECK:
                                        ZEND_OP2(opline).opline_num -= shiftlist[ZEND_OP2(opline).opline_num];
                                        break;
+                               case ZEND_FE_FETCH_R:
+                               case ZEND_FE_FETCH_RW:
+                                       opline->extended_value -= shiftlist[opline->extended_value];
+                                       break;
                                case ZEND_JMPZNZ:
                                        ZEND_OP2(opline).opline_num -= shiftlist[ZEND_OP2(opline).opline_num];
                                        opline->extended_value -= shiftlist[opline->extended_value];
index 79a4d8321d0d192a36586e77bfb171cd162de043..e0dfbfa541c6257d6ce3d6bc022b02470eaa6d8e 100644 (file)
@@ -515,11 +515,13 @@ static void zend_accel_optimize(zend_op_array      *op_array,
                        case ZEND_NEW:
                        case ZEND_FE_RESET_R:
                        case ZEND_FE_RESET_RW:
-                       case ZEND_FE_FETCH_R:
-                       case ZEND_FE_FETCH_RW:
                        case ZEND_ASSERT_CHECK:
                                ZEND_PASS_TWO_UNDO_JMP_TARGET(op_array, opline, ZEND_OP2(opline));
                                break;
+                       case ZEND_FE_FETCH_R:
+                       case ZEND_FE_FETCH_RW:
+                               opline->extended_value = ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value);
+                               break;
                }
                opline++;
        }
@@ -558,11 +560,13 @@ static void zend_accel_optimize(zend_op_array      *op_array,
                        case ZEND_NEW:
                        case ZEND_FE_RESET_R:
                        case ZEND_FE_RESET_RW:
-                       case ZEND_FE_FETCH_R:
-                       case ZEND_FE_FETCH_RW:
                        case ZEND_ASSERT_CHECK:
                                ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, ZEND_OP2(opline));
                                break;
+                       case ZEND_FE_FETCH_R:
+                       case ZEND_FE_FETCH_RW:
+                               opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, opline->extended_value);
+                               break;
                }
                ZEND_VM_SET_OPCODE_HANDLER(opline);
                opline++;
index 353eecb7f25ced2eb3558609ec1ddf4262062d6c..52ee49d5e1056841b1ecc64587ac958d9a4e6a20 100644 (file)
@@ -406,11 +406,13 @@ static void zend_file_cache_serialize_op_array(zend_op_array            *op_arra
                                case ZEND_NEW:
                                case ZEND_FE_RESET_R:
                                case ZEND_FE_RESET_RW:
-                               case ZEND_FE_FETCH_R:
-                               case ZEND_FE_FETCH_RW:
                                case ZEND_ASSERT_CHECK:
                                        SERIALIZE_PTR(opline->op2.jmp_addr);
                                        break;
+                               case ZEND_FE_FETCH_R:
+                               case ZEND_FE_FETCH_RW:
+                                       /* relative extended_value don't have to be changed */
+                                       break;
                        }
 # endif
                        opline++;
@@ -927,11 +929,13 @@ static void zend_file_cache_unserialize_op_array(zend_op_array           *op_arr
                                case ZEND_NEW:
                                case ZEND_FE_RESET_R:
                                case ZEND_FE_RESET_RW:
-                               case ZEND_FE_FETCH_R:
-                               case ZEND_FE_FETCH_RW:
                                case ZEND_ASSERT_CHECK:
                                        UNSERIALIZE_PTR(opline->op2.jmp_addr);
                                        break;
+                               case ZEND_FE_FETCH_R:
+                               case ZEND_FE_FETCH_RW:
+                                       /* relative extended_value don't have to be changed */
+                                       break;
                        }
 # endif
                        ZEND_VM_SET_OPCODE_HANDLER(opline);
index 4aee6fb628b3412084561ec8325bec9b5ab49545..d1c1bb279a8d03b2369e924a1d74a8d3b0988783 100644 (file)
@@ -518,11 +518,13 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc
                                        case ZEND_NEW:
                                        case ZEND_FE_RESET_R:
                                        case ZEND_FE_RESET_RW:
-                                       case ZEND_FE_FETCH_R:
-                                       case ZEND_FE_FETCH_RW:
                                        case ZEND_ASSERT_CHECK:
                                                ZEND_OP2(opline).jmp_addr = &new_opcodes[ZEND_OP2(opline).jmp_addr - op_array->opcodes];
                                                break;
+                                       case ZEND_FE_FETCH_R:
+                                       case ZEND_FE_FETCH_RW:
+                                               /* relative extended_value don't have to be changed */
+                                               break;
                                }
                        }
 # endif