From: Dmitry Stogov Date: Thu, 22 Apr 2010 11:56:45 +0000 (+0000) Subject: ZEND_RETURN is splitted into two new instructions ZEND_RETURN and ZEND_RETURN_BY_REF X-Git-Tag: php-5.4.0alpha1~191^2~1699 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fb9d95e5a4e941f0fef9639a55dea5cb2c2d49da;p=php ZEND_RETURN is splitted into two new instructions ZEND_RETURN and ZEND_RETURN_BY_REF --- diff --git a/NEWS b/NEWS index 14d9dcde44..cb4f239c3e 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,8 @@ . ZEND_RECV now always has IS_CV as its result . ZEND_CATCH now has to be used only with constant class names . ZEND_FETCH_DIM_? may fetch array and dimension operans in a different order + . ZEND_RETURN is splitted into two new instructions ZEND_RETURN and + ZEND_RETURN_BY_REF - Added concept of interned strings. All strings constants known at compile time are allocated in a single copy and never changed. (Dmitry) - Added an optimization which saves memory and emalloc/efree calls for empty diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index ef27913e47..c523a3dfa0 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2439,7 +2439,7 @@ void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC) /* {{{ */ opline = get_next_op(CG(active_op_array) TSRMLS_CC); - opline->opcode = ZEND_RETURN; + opline->opcode = (CG(active_op_array)->return_reference == ZEND_RETURN_REF) ? ZEND_RETURN_BY_REF : ZEND_RETURN; if (expr) { SET_NODE(opline->op1, expr); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 8fb3f85530..e8c556fc78 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2705,6 +2705,43 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, CONST, ANY) } ZEND_VM_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY) +{ + USE_OPLINE + zval *retval_ptr; + zend_free_op free_op1; + + SAVE_OPLINE(); + retval_ptr = GET_OP1_ZVAL_PTR(BP_VAR_R); + + if (!EG(return_value_ptr_ptr)) { + if (OP1_TYPE == IS_TMP_VAR) { + FREE_OP1(); + } + } else if (!IS_OP1_TMP_FREE()) { /* Not a temp var */ + if (OP1_TYPE == IS_CONST || + (PZVAL_IS_REF(retval_ptr) && Z_REFCOUNT_P(retval_ptr) > 0)) { + zval *ret; + + ALLOC_ZVAL(ret); + INIT_PZVAL_COPY(ret, retval_ptr); + zval_copy_ctor(ret); + *EG(return_value_ptr_ptr) = ret; + } else { + *EG(return_value_ptr_ptr) = retval_ptr; + Z_ADDREF_P(retval_ptr); + } + } else { + zval *ret; + + ALLOC_ZVAL(ret); + INIT_PZVAL_COPY(ret, retval_ptr); + *EG(return_value_ptr_ptr) = ret; + } + FREE_OP1_IF_VAR(); + ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper); +} + +ZEND_VM_HANDLER(111, ZEND_RETURN_BY_REF, CONST|TMP|VAR|CV, ANY) { USE_OPLINE zval *retval_ptr; @@ -2712,12 +2749,32 @@ ZEND_VM_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY) zend_free_op free_op1; SAVE_OPLINE(); - if (UNEXPECTED(EG(active_op_array)->return_reference == ZEND_RETURN_REF)) { + do { if (OP1_TYPE == IS_CONST || OP1_TYPE == IS_TMP_VAR) { /* Not supposed to happen, but we'll allow it */ zend_error(E_NOTICE, "Only variable references should be returned by reference"); - ZEND_VM_C_GOTO(return_by_value); + + retval_ptr = GET_OP1_ZVAL_PTR(BP_VAR_R); + if (!EG(return_value_ptr_ptr)) { + if (OP1_TYPE == IS_TMP_VAR) { + FREE_OP1(); + } + } else if (!IS_OP1_TMP_FREE()) { /* Not a temp var */ + zval *ret; + + ALLOC_ZVAL(ret); + INIT_PZVAL_COPY(ret, retval_ptr); + zval_copy_ctor(ret); + *EG(return_value_ptr_ptr) = ret; + } else { + zval *ret; + + ALLOC_ZVAL(ret); + INIT_PZVAL_COPY(ret, retval_ptr); + *EG(return_value_ptr_ptr) = ret; + } + break; } retval_ptr_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W); @@ -2730,11 +2787,13 @@ ZEND_VM_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY) if (opline->extended_value == ZEND_RETURNS_FUNCTION && EX_T(opline->op1.var).var.fcall_returned_reference) { } else if (EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr) { - if (OP1_TYPE == IS_VAR && !OP1_FREE) { - PZVAL_LOCK(*retval_ptr_ptr); /* undo the effect of get_zval_ptr_ptr() */ - } zend_error(E_NOTICE, "Only variable references should be returned by reference"); - ZEND_VM_C_GOTO(return_by_value); + if (EG(return_value_ptr_ptr)) { + retval_ptr = *retval_ptr_ptr; + *EG(return_value_ptr_ptr) = retval_ptr; + Z_ADDREF_P(retval_ptr); + } + break; } } @@ -2742,43 +2801,12 @@ ZEND_VM_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY) SEPARATE_ZVAL_TO_MAKE_IS_REF(retval_ptr_ptr); Z_ADDREF_PP(retval_ptr_ptr); - (*EG(return_value_ptr_ptr)) = (*retval_ptr_ptr); + *EG(return_value_ptr_ptr) = *retval_ptr_ptr; } - FREE_OP1_IF_VAR(); - ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper); - } else { -ZEND_VM_C_LABEL(return_by_value): - - retval_ptr = GET_OP1_ZVAL_PTR(BP_VAR_R); - - if (!EG(return_value_ptr_ptr)) { - if (OP1_TYPE == IS_TMP_VAR) { - FREE_OP1(); - } - } else if (!IS_OP1_TMP_FREE()) { /* Not a temp var */ - if (OP1_TYPE == IS_CONST || - EG(active_op_array)->return_reference == ZEND_RETURN_REF || - (PZVAL_IS_REF(retval_ptr) && Z_REFCOUNT_P(retval_ptr) > 0)) { - zval *ret; + } while (0); - ALLOC_ZVAL(ret); - INIT_PZVAL_COPY(ret, retval_ptr); - zval_copy_ctor(ret); - *EG(return_value_ptr_ptr) = ret; - } else { - *EG(return_value_ptr_ptr) = retval_ptr; - Z_ADDREF_P(retval_ptr); - } - } else { - zval *ret; - - ALLOC_ZVAL(ret); - INIT_PZVAL_COPY(ret, retval_ptr); - *EG(return_value_ptr_ptr) = ret; - } - FREE_OP1_IF_VAR(); - ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper); - } + FREE_OP1_IF_VAR(); + ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper); } ZEND_VM_HANDLER(108, ZEND_THROW, CONST|TMP|VAR|CV, ANY) diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index aa93d4d950..2b1b31767a 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1765,6 +1765,43 @@ static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A } static int ZEND_FASTCALL ZEND_RETURN_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *retval_ptr; + + + SAVE_OPLINE(); + retval_ptr = opline->op1.zv; + + if (!EG(return_value_ptr_ptr)) { + if (IS_CONST == IS_TMP_VAR) { + + } + } else if (!0) { /* Not a temp var */ + if (IS_CONST == IS_CONST || + (PZVAL_IS_REF(retval_ptr) && Z_REFCOUNT_P(retval_ptr) > 0)) { + zval *ret; + + ALLOC_ZVAL(ret); + INIT_PZVAL_COPY(ret, retval_ptr); + zval_copy_ctor(ret); + *EG(return_value_ptr_ptr) = ret; + } else { + *EG(return_value_ptr_ptr) = retval_ptr; + Z_ADDREF_P(retval_ptr); + } + } else { + zval *ret; + + ALLOC_ZVAL(ret); + INIT_PZVAL_COPY(ret, retval_ptr); + *EG(return_value_ptr_ptr) = ret; + } + + return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); +} + +static int ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zval *retval_ptr; @@ -1772,12 +1809,32 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARG SAVE_OPLINE(); - if (UNEXPECTED(EG(active_op_array)->return_reference == ZEND_RETURN_REF)) { + do { if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) { /* Not supposed to happen, but we'll allow it */ zend_error(E_NOTICE, "Only variable references should be returned by reference"); - goto return_by_value; + + retval_ptr = opline->op1.zv; + if (!EG(return_value_ptr_ptr)) { + if (IS_CONST == IS_TMP_VAR) { + + } + } else if (!0) { /* Not a temp var */ + zval *ret; + + ALLOC_ZVAL(ret); + INIT_PZVAL_COPY(ret, retval_ptr); + zval_copy_ctor(ret); + *EG(return_value_ptr_ptr) = ret; + } else { + zval *ret; + + ALLOC_ZVAL(ret); + INIT_PZVAL_COPY(ret, retval_ptr); + *EG(return_value_ptr_ptr) = ret; + } + break; } retval_ptr_ptr = NULL; @@ -1790,11 +1847,13 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARG if (opline->extended_value == ZEND_RETURNS_FUNCTION && EX_T(opline->op1.var).var.fcall_returned_reference) { } else if (EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr) { - if (IS_CONST == IS_VAR && !0) { - PZVAL_LOCK(*retval_ptr_ptr); /* undo the effect of get_zval_ptr_ptr() */ - } zend_error(E_NOTICE, "Only variable references should be returned by reference"); - goto return_by_value; + if (EG(return_value_ptr_ptr)) { + retval_ptr = *retval_ptr_ptr; + *EG(return_value_ptr_ptr) = retval_ptr; + Z_ADDREF_P(retval_ptr); + } + break; } } @@ -1802,43 +1861,11 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARG SEPARATE_ZVAL_TO_MAKE_IS_REF(retval_ptr_ptr); Z_ADDREF_PP(retval_ptr_ptr); - (*EG(return_value_ptr_ptr)) = (*retval_ptr_ptr); - } - - return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } else { -return_by_value: - - retval_ptr = opline->op1.zv; - - if (!EG(return_value_ptr_ptr)) { - if (IS_CONST == IS_TMP_VAR) { - - } - } else if (!0) { /* Not a temp var */ - if (IS_CONST == IS_CONST || - EG(active_op_array)->return_reference == ZEND_RETURN_REF || - (PZVAL_IS_REF(retval_ptr) && Z_REFCOUNT_P(retval_ptr) > 0)) { - zval *ret; - - ALLOC_ZVAL(ret); - INIT_PZVAL_COPY(ret, retval_ptr); - zval_copy_ctor(ret); - *EG(return_value_ptr_ptr) = ret; - } else { - *EG(return_value_ptr_ptr) = retval_ptr; - Z_ADDREF_P(retval_ptr); - } - } else { - zval *ret; - - ALLOC_ZVAL(ret); - INIT_PZVAL_COPY(ret, retval_ptr); - *EG(return_value_ptr_ptr) = ret; + *EG(return_value_ptr_ptr) = *retval_ptr_ptr; } + } while (0); - return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } + return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_THROW_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -5305,6 +5332,43 @@ static int ZEND_FASTCALL ZEND_FREE_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } static int ZEND_FASTCALL ZEND_RETURN_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *retval_ptr; + zend_free_op free_op1; + + SAVE_OPLINE(); + retval_ptr = _get_zval_ptr_tmp(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC); + + if (!EG(return_value_ptr_ptr)) { + if (IS_TMP_VAR == IS_TMP_VAR) { + zval_dtor(free_op1.var); + } + } else if (!1) { /* Not a temp var */ + if (IS_TMP_VAR == IS_CONST || + (PZVAL_IS_REF(retval_ptr) && Z_REFCOUNT_P(retval_ptr) > 0)) { + zval *ret; + + ALLOC_ZVAL(ret); + INIT_PZVAL_COPY(ret, retval_ptr); + zval_copy_ctor(ret); + *EG(return_value_ptr_ptr) = ret; + } else { + *EG(return_value_ptr_ptr) = retval_ptr; + Z_ADDREF_P(retval_ptr); + } + } else { + zval *ret; + + ALLOC_ZVAL(ret); + INIT_PZVAL_COPY(ret, retval_ptr); + *EG(return_value_ptr_ptr) = ret; + } + + return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); +} + +static int ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zval *retval_ptr; @@ -5312,12 +5376,32 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_free_op free_op1; SAVE_OPLINE(); - if (UNEXPECTED(EG(active_op_array)->return_reference == ZEND_RETURN_REF)) { + do { if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) { /* Not supposed to happen, but we'll allow it */ zend_error(E_NOTICE, "Only variable references should be returned by reference"); - goto return_by_value; + + retval_ptr = _get_zval_ptr_tmp(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC); + if (!EG(return_value_ptr_ptr)) { + if (IS_TMP_VAR == IS_TMP_VAR) { + zval_dtor(free_op1.var); + } + } else if (!1) { /* Not a temp var */ + zval *ret; + + ALLOC_ZVAL(ret); + INIT_PZVAL_COPY(ret, retval_ptr); + zval_copy_ctor(ret); + *EG(return_value_ptr_ptr) = ret; + } else { + zval *ret; + + ALLOC_ZVAL(ret); + INIT_PZVAL_COPY(ret, retval_ptr); + *EG(return_value_ptr_ptr) = ret; + } + break; } retval_ptr_ptr = NULL; @@ -5330,11 +5414,13 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) if (opline->extended_value == ZEND_RETURNS_FUNCTION && EX_T(opline->op1.var).var.fcall_returned_reference) { } else if (EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr) { - if (IS_TMP_VAR == IS_VAR && !1) { - PZVAL_LOCK(*retval_ptr_ptr); /* undo the effect of get_zval_ptr_ptr() */ - } zend_error(E_NOTICE, "Only variable references should be returned by reference"); - goto return_by_value; + if (EG(return_value_ptr_ptr)) { + retval_ptr = *retval_ptr_ptr; + *EG(return_value_ptr_ptr) = retval_ptr; + Z_ADDREF_P(retval_ptr); + } + break; } } @@ -5342,43 +5428,11 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) SEPARATE_ZVAL_TO_MAKE_IS_REF(retval_ptr_ptr); Z_ADDREF_PP(retval_ptr_ptr); - (*EG(return_value_ptr_ptr)) = (*retval_ptr_ptr); - } - - return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } else { -return_by_value: - - retval_ptr = _get_zval_ptr_tmp(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC); - - if (!EG(return_value_ptr_ptr)) { - if (IS_TMP_VAR == IS_TMP_VAR) { - zval_dtor(free_op1.var); - } - } else if (!1) { /* Not a temp var */ - if (IS_TMP_VAR == IS_CONST || - EG(active_op_array)->return_reference == ZEND_RETURN_REF || - (PZVAL_IS_REF(retval_ptr) && Z_REFCOUNT_P(retval_ptr) > 0)) { - zval *ret; - - ALLOC_ZVAL(ret); - INIT_PZVAL_COPY(ret, retval_ptr); - zval_copy_ctor(ret); - *EG(return_value_ptr_ptr) = ret; - } else { - *EG(return_value_ptr_ptr) = retval_ptr; - Z_ADDREF_P(retval_ptr); - } - } else { - zval *ret; - - ALLOC_ZVAL(ret); - INIT_PZVAL_COPY(ret, retval_ptr); - *EG(return_value_ptr_ptr) = ret; + *EG(return_value_ptr_ptr) = *retval_ptr_ptr; } + } while (0); - return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } + return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_THROW_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -8828,6 +8882,43 @@ static int ZEND_FASTCALL ZEND_JMPNZ_EX_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG } static int ZEND_FASTCALL ZEND_RETURN_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *retval_ptr; + zend_free_op free_op1; + + SAVE_OPLINE(); + retval_ptr = _get_zval_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC); + + if (!EG(return_value_ptr_ptr)) { + if (IS_VAR == IS_TMP_VAR) { + if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; + } + } else if (!0) { /* Not a temp var */ + if (IS_VAR == IS_CONST || + (PZVAL_IS_REF(retval_ptr) && Z_REFCOUNT_P(retval_ptr) > 0)) { + zval *ret; + + ALLOC_ZVAL(ret); + INIT_PZVAL_COPY(ret, retval_ptr); + zval_copy_ctor(ret); + *EG(return_value_ptr_ptr) = ret; + } else { + *EG(return_value_ptr_ptr) = retval_ptr; + Z_ADDREF_P(retval_ptr); + } + } else { + zval *ret; + + ALLOC_ZVAL(ret); + INIT_PZVAL_COPY(ret, retval_ptr); + *EG(return_value_ptr_ptr) = ret; + } + if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; + return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); +} + +static int ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zval *retval_ptr; @@ -8835,12 +8926,32 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_free_op free_op1; SAVE_OPLINE(); - if (UNEXPECTED(EG(active_op_array)->return_reference == ZEND_RETURN_REF)) { + do { if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) { /* Not supposed to happen, but we'll allow it */ zend_error(E_NOTICE, "Only variable references should be returned by reference"); - goto return_by_value; + + retval_ptr = _get_zval_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC); + if (!EG(return_value_ptr_ptr)) { + if (IS_VAR == IS_TMP_VAR) { + if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; + } + } else if (!0) { /* Not a temp var */ + zval *ret; + + ALLOC_ZVAL(ret); + INIT_PZVAL_COPY(ret, retval_ptr); + zval_copy_ctor(ret); + *EG(return_value_ptr_ptr) = ret; + } else { + zval *ret; + + ALLOC_ZVAL(ret); + INIT_PZVAL_COPY(ret, retval_ptr); + *EG(return_value_ptr_ptr) = ret; + } + break; } retval_ptr_ptr = _get_zval_ptr_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC); @@ -8853,11 +8964,13 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) if (opline->extended_value == ZEND_RETURNS_FUNCTION && EX_T(opline->op1.var).var.fcall_returned_reference) { } else if (EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr) { - if (IS_VAR == IS_VAR && !(free_op1.var != NULL)) { - PZVAL_LOCK(*retval_ptr_ptr); /* undo the effect of get_zval_ptr_ptr() */ - } zend_error(E_NOTICE, "Only variable references should be returned by reference"); - goto return_by_value; + if (EG(return_value_ptr_ptr)) { + retval_ptr = *retval_ptr_ptr; + *EG(return_value_ptr_ptr) = retval_ptr; + Z_ADDREF_P(retval_ptr); + } + break; } } @@ -8865,43 +8978,12 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) SEPARATE_ZVAL_TO_MAKE_IS_REF(retval_ptr_ptr); Z_ADDREF_PP(retval_ptr_ptr); - (*EG(return_value_ptr_ptr)) = (*retval_ptr_ptr); + *EG(return_value_ptr_ptr) = *retval_ptr_ptr; } - if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; - return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } else { -return_by_value: - - retval_ptr = _get_zval_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC); - - if (!EG(return_value_ptr_ptr)) { - if (IS_VAR == IS_TMP_VAR) { - if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; - } - } else if (!0) { /* Not a temp var */ - if (IS_VAR == IS_CONST || - EG(active_op_array)->return_reference == ZEND_RETURN_REF || - (PZVAL_IS_REF(retval_ptr) && Z_REFCOUNT_P(retval_ptr) > 0)) { - zval *ret; + } while (0); - ALLOC_ZVAL(ret); - INIT_PZVAL_COPY(ret, retval_ptr); - zval_copy_ctor(ret); - *EG(return_value_ptr_ptr) = ret; - } else { - *EG(return_value_ptr_ptr) = retval_ptr; - Z_ADDREF_P(retval_ptr); - } - } else { - zval *ret; - - ALLOC_ZVAL(ret); - INIT_PZVAL_COPY(ret, retval_ptr); - *EG(return_value_ptr_ptr) = ret; - } - if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; - return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } + if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; + return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_THROW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -23941,6 +24023,43 @@ static int ZEND_FASTCALL ZEND_JMPNZ_EX_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS } static int ZEND_FASTCALL ZEND_RETURN_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *retval_ptr; + + + SAVE_OPLINE(); + retval_ptr = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op1.var TSRMLS_CC); + + if (!EG(return_value_ptr_ptr)) { + if (IS_CV == IS_TMP_VAR) { + + } + } else if (!0) { /* Not a temp var */ + if (IS_CV == IS_CONST || + (PZVAL_IS_REF(retval_ptr) && Z_REFCOUNT_P(retval_ptr) > 0)) { + zval *ret; + + ALLOC_ZVAL(ret); + INIT_PZVAL_COPY(ret, retval_ptr); + zval_copy_ctor(ret); + *EG(return_value_ptr_ptr) = ret; + } else { + *EG(return_value_ptr_ptr) = retval_ptr; + Z_ADDREF_P(retval_ptr); + } + } else { + zval *ret; + + ALLOC_ZVAL(ret); + INIT_PZVAL_COPY(ret, retval_ptr); + *EG(return_value_ptr_ptr) = ret; + } + + return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); +} + +static int ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zval *retval_ptr; @@ -23948,12 +24067,32 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) SAVE_OPLINE(); - if (UNEXPECTED(EG(active_op_array)->return_reference == ZEND_RETURN_REF)) { + do { if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR) { /* Not supposed to happen, but we'll allow it */ zend_error(E_NOTICE, "Only variable references should be returned by reference"); - goto return_by_value; + + retval_ptr = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op1.var TSRMLS_CC); + if (!EG(return_value_ptr_ptr)) { + if (IS_CV == IS_TMP_VAR) { + + } + } else if (!0) { /* Not a temp var */ + zval *ret; + + ALLOC_ZVAL(ret); + INIT_PZVAL_COPY(ret, retval_ptr); + zval_copy_ctor(ret); + *EG(return_value_ptr_ptr) = ret; + } else { + zval *ret; + + ALLOC_ZVAL(ret); + INIT_PZVAL_COPY(ret, retval_ptr); + *EG(return_value_ptr_ptr) = ret; + } + break; } retval_ptr_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(EX_CVs(), opline->op1.var TSRMLS_CC); @@ -23966,11 +24105,13 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) if (opline->extended_value == ZEND_RETURNS_FUNCTION && EX_T(opline->op1.var).var.fcall_returned_reference) { } else if (EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr) { - if (IS_CV == IS_VAR && !0) { - PZVAL_LOCK(*retval_ptr_ptr); /* undo the effect of get_zval_ptr_ptr() */ - } zend_error(E_NOTICE, "Only variable references should be returned by reference"); - goto return_by_value; + if (EG(return_value_ptr_ptr)) { + retval_ptr = *retval_ptr_ptr; + *EG(return_value_ptr_ptr) = retval_ptr; + Z_ADDREF_P(retval_ptr); + } + break; } } @@ -23978,43 +24119,11 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) SEPARATE_ZVAL_TO_MAKE_IS_REF(retval_ptr_ptr); Z_ADDREF_PP(retval_ptr_ptr); - (*EG(return_value_ptr_ptr)) = (*retval_ptr_ptr); - } - - return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } else { -return_by_value: - - retval_ptr = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op1.var TSRMLS_CC); - - if (!EG(return_value_ptr_ptr)) { - if (IS_CV == IS_TMP_VAR) { - - } - } else if (!0) { /* Not a temp var */ - if (IS_CV == IS_CONST || - EG(active_op_array)->return_reference == ZEND_RETURN_REF || - (PZVAL_IS_REF(retval_ptr) && Z_REFCOUNT_P(retval_ptr) > 0)) { - zval *ret; - - ALLOC_ZVAL(ret); - INIT_PZVAL_COPY(ret, retval_ptr); - zval_copy_ctor(ret); - *EG(return_value_ptr_ptr) = ret; - } else { - *EG(return_value_ptr_ptr) = retval_ptr; - Z_ADDREF_P(retval_ptr); - } - } else { - zval *ret; - - ALLOC_ZVAL(ret); - INIT_PZVAL_COPY(ret, retval_ptr); - *EG(return_value_ptr_ptr) = ret; + *EG(return_value_ptr_ptr) = *retval_ptr_ptr; } + } while (0); - return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } + return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_THROW_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -35483,31 +35592,31 @@ void zend_init_opcodes_handlers(void) ZEND_CLONE_SPEC_CV_HANDLER, ZEND_CLONE_SPEC_CV_HANDLER, ZEND_CLONE_SPEC_CV_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, + ZEND_RETURN_BY_REF_SPEC_CONST_HANDLER, + ZEND_RETURN_BY_REF_SPEC_CONST_HANDLER, + ZEND_RETURN_BY_REF_SPEC_CONST_HANDLER, + ZEND_RETURN_BY_REF_SPEC_CONST_HANDLER, + ZEND_RETURN_BY_REF_SPEC_CONST_HANDLER, + ZEND_RETURN_BY_REF_SPEC_TMP_HANDLER, + ZEND_RETURN_BY_REF_SPEC_TMP_HANDLER, + ZEND_RETURN_BY_REF_SPEC_TMP_HANDLER, + ZEND_RETURN_BY_REF_SPEC_TMP_HANDLER, + ZEND_RETURN_BY_REF_SPEC_TMP_HANDLER, + ZEND_RETURN_BY_REF_SPEC_VAR_HANDLER, + ZEND_RETURN_BY_REF_SPEC_VAR_HANDLER, + ZEND_RETURN_BY_REF_SPEC_VAR_HANDLER, + ZEND_RETURN_BY_REF_SPEC_VAR_HANDLER, + ZEND_RETURN_BY_REF_SPEC_VAR_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_RETURN_BY_REF_SPEC_CV_HANDLER, + ZEND_RETURN_BY_REF_SPEC_CV_HANDLER, + ZEND_RETURN_BY_REF_SPEC_CV_HANDLER, + ZEND_RETURN_BY_REF_SPEC_CV_HANDLER, + ZEND_RETURN_BY_REF_SPEC_CV_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h index d048a8576d..10225c427c 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -129,6 +129,7 @@ #define ZEND_THROW 108 #define ZEND_FETCH_CLASS 109 #define ZEND_CLONE 110 +#define ZEND_RETURN_BY_REF 111 #define ZEND_INIT_METHOD_CALL 112 #define ZEND_INIT_STATIC_METHOD_CALL 113 #define ZEND_ISSET_ISEMPTY_VAR 114