From: Dmitry Stogov Date: Wed, 13 May 2015 09:55:42 +0000 (+0300) Subject: Merged FE_FETCH_R[W] with the following ASSIGN[_REF] when assigne to CV. X-Git-Tag: PRE_PHP7_NSAPI_REMOVAL~42^2~92 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d72a94468efc9016b0bfbf80658b73702e320025;p=php Merged FE_FETCH_R[W] with the following ASSIGN[_REF] when assigne to CV. --- diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 2606304afb..78f8ae3207 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -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); diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index f523b279bb..d29014d3b2 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -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 */ diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 43ba64ad3f..f24fc9f193 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -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); diff --git a/Zend/zend_types.h b/Zend/zend_types.h index a7d8d99611..d66da1eade 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -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) { \ diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index eec2891ad7..facc1f8696 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -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(); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index acb0151dd4..d4902ef972 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -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(); diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c index a757d55fce..275e3f5fa2 100644 --- a/ext/opcache/Optimizer/block_pass.c +++ b/ext/opcache/Optimizer/block_pass.c @@ -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 (oplineop1); - 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)] && diff --git a/ext/opcache/Optimizer/nop_removal.c b/ext/opcache/Optimizer/nop_removal.c index 4a985df17c..20510b4163 100644 --- a/ext/opcache/Optimizer/nop_removal.c +++ b/ext/opcache/Optimizer/nop_removal.c @@ -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]; diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c index 79a4d8321d..e0dfbfa541 100644 --- a/ext/opcache/Optimizer/zend_optimizer.c +++ b/ext/opcache/Optimizer/zend_optimizer.c @@ -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++; diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c index 353eecb7f2..52ee49d5e1 100644 --- a/ext/opcache/zend_file_cache.c +++ b/ext/opcache/zend_file_cache.c @@ -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); diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index 4aee6fb628..d1c1bb279a 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -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