]> granicus.if.org Git - php/commitdiff
ZEND_RETURN is splitted into two new instructions ZEND_RETURN and ZEND_RETURN_BY_REF
authorDmitry Stogov <dmitry@php.net>
Thu, 22 Apr 2010 11:56:45 +0000 (11:56 +0000)
committerDmitry Stogov <dmitry@php.net>
Thu, 22 Apr 2010 11:56:45 +0000 (11:56 +0000)
NEWS
Zend/zend_compile.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
Zend/zend_vm_opcodes.h

diff --git a/NEWS b/NEWS
index 14d9dcde440d35734882dc0e6ecde257c7338de7..cb4f239c3e4e89bbbf5e564dfcfa98b4052dfa83 100644 (file)
--- 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
index ef27913e47f6d89382516aeaad5b8707f4731f6f..c523a3dfa0693ca91b80711a7a6cc8bc2c24f123 100644 (file)
@@ -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);
index 8fb3f855301504124d7ff10040c9971114f63441..e8c556fc78b5c399ccf3c07c1d3a98ec8ed4b267 100644 (file)
@@ -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)
index aa93d4d9504022db3ddb2a70a9e872fa2f0cf942..2b1b31767aecf77a73fe64fd402f956d20a5322a 100644 (file)
@@ -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,
index d048a8576d586c1370626f5ff2fb99e464340de2..10225c427c88d79596c693877a6a5266325b9bbd 100644 (file)
 #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