]> granicus.if.org Git - php/commitdiff
Optimized ZEND_RETURN opcode to not allocate and copy return value if it is not
authorDmitry Stogov <dmitry@php.net>
Fri, 11 Apr 2008 09:43:28 +0000 (09:43 +0000)
committerDmitry Stogov <dmitry@php.net>
Fri, 11 Apr 2008 09:43:28 +0000 (09:43 +0000)
used.

NEWS
Zend/zend.c
Zend/zend_execute_API.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

diff --git a/NEWS b/NEWS
index 6b889dc907c921e40e05de255a0c4af593f24f54..bf0413a2f43efcf57c38571c703d89a4ae7690f5 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -91,6 +91,8 @@ PHP                                                                        NEWS
 - Added forward_static_call(_array) to complete LSB. (Mike Lively)
 
 - Improved PHP runtime speed and memory usage:
+  . Optimized ZEND_RETURN opcode to not allocate and copy return value if it is
+    not used. (Dmitry)
   . Replaced flex based scanner with re2c based scanner. (Marcus, Nuno, Scott)
   . Added garbage collector. (David Wang, Dmitry).
   . Improved PHP binary size and startup speed with GCC4 visibility control.
index 71b39fcb749e4bd0686c5c1f59753d728faa7dae..b6329e9b7c39a3547fc46eb976368f94c8b0799f 100644 (file)
@@ -1150,7 +1150,6 @@ ZEND_API int zend_execute_scripts(int type TSRMLS_DC, zval **retval, int file_co
        zend_file_handle *file_handle;
        zend_op_array *orig_op_array = EG(active_op_array);
        zval **orig_retval_ptr_ptr = EG(return_value_ptr_ptr);
-       zval *local_retval = NULL;
 
        va_start(files, file_count);
        for (i = 0; i < file_count; i++) {
@@ -1165,7 +1164,7 @@ ZEND_API int zend_execute_scripts(int type TSRMLS_DC, zval **retval, int file_co
                }
                zend_destroy_file_handle(file_handle TSRMLS_CC);
                if (EG(active_op_array)) {
-                       EG(return_value_ptr_ptr) = retval ? retval : &local_retval;
+                       EG(return_value_ptr_ptr) = retval ? retval : NULL;
                        zend_execute(EG(active_op_array) TSRMLS_CC);
                        if (EG(exception)) {
                                if (EG(user_exception_handler)) {
@@ -1195,13 +1194,6 @@ ZEND_API int zend_execute_scripts(int type TSRMLS_DC, zval **retval, int file_co
                                } else {
                                        zend_exception_error(EG(exception) TSRMLS_CC);
                                }
-                               if (retval == NULL && *EG(return_value_ptr_ptr) != NULL) {
-                                       zval_ptr_dtor(EG(return_value_ptr_ptr));
-                                       local_retval = NULL;
-                               }
-                       } else if (!retval && *EG(return_value_ptr_ptr)) {
-                               zval_ptr_dtor(EG(return_value_ptr_ptr));
-                               local_retval = NULL;
                        }
                        destroy_op_array(EG(active_op_array) TSRMLS_CC);
                        efree(EG(active_op_array));
index 98b17376cde5b6ff6675e1837d7f9ec45413139c..74ffc1c56caf4ed493e1827564b7c3046c812938 100644 (file)
@@ -1273,7 +1273,7 @@ ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name TSR
                Z_STRVAL(pv)[Z_STRLEN(pv)] = '\0';
        } else {
                Z_STRLEN(pv) = strlen(str);
-               Z_STRVAL(pv) = estrndup(str, Z_STRLEN(pv));
+               Z_STRVAL(pv) = str;
        }
        Z_TYPE(pv) = IS_STRING;
 
@@ -1317,7 +1317,9 @@ ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name TSR
        } else {
                retval = FAILURE;
        }
-       zval_dtor(&pv);
+       if (retval_ptr) {
+               zval_dtor(&pv);
+       }
        return retval;
 }
 /* }}} */
@@ -1339,7 +1341,6 @@ void execute_new_code(TSRMLS_D) /* {{{ */
 {
        zend_op *opline, *end;
        zend_op *ret_opline;
-       zval *local_retval=NULL;
 
        if (!(CG(active_op_array)->fn_flags & ZEND_ACC_INTERACTIVE)
                || CG(active_op_array)->backpatch_count>0
@@ -1393,12 +1394,9 @@ void execute_new_code(TSRMLS_D) /* {{{ */
        
        zend_release_labels(TSRMLS_C);
        
-       EG(return_value_ptr_ptr) = &local_retval;
+       EG(return_value_ptr_ptr) = NULL;
        EG(active_op_array) = CG(active_op_array);
        zend_execute(CG(active_op_array) TSRMLS_CC);
-       if (local_retval) {
-               zval_ptr_dtor(&local_retval);
-       }
 
        if (EG(exception)) {
                zend_exception_error(EG(exception) TSRMLS_CC);
index 1998a3c77e36d752c503e3582984caa696f6ee3f..839829a97721a46080da3f927f6d24ff65f3e8d4 100644 (file)
@@ -2167,7 +2167,7 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
                        zend_hash_init(EG(active_symbol_table), 0, NULL, ZVAL_PTR_DTOR, 0);
                        /*printf("Cache miss!  Initialized %x\n", EG(active_symbol_table));*/
                }
-               EG(return_value_ptr_ptr) = &EX_T(opline->result.u.var).var.ptr;
+               EG(return_value_ptr_ptr) = RETURN_VALUE_USED(opline) ? &EX_T(opline->result.u.var).var.ptr : NULL;
                EG(active_op_array) = (zend_op_array *) EX(function_state).function;
 
                zend_execute(EG(active_op_array) TSRMLS_CC);
@@ -2177,8 +2177,6 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
                        if (!EX_T(opline->result.u.var).var.ptr && !EG(exception)) {
                                ALLOC_INIT_ZVAL(EX_T(opline->result.u.var).var.ptr);
                        }
-               } else if (EX_T(opline->result.u.var).var.ptr) {
-                       zval_ptr_dtor(&EX_T(opline->result.u.var).var.ptr);
                }
 
                EG(opline_ptr) = &EX(opline);
@@ -2313,16 +2311,22 @@ 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);
+               if (EG(return_value_ptr_ptr)) {
+                       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);
+               }
        } else {
 ZEND_VM_C_LABEL(return_by_value):
 
                retval_ptr = GET_OP1_ZVAL_PTR(BP_VAR_R);
 
-               if (!IS_OP1_TMP_FREE()) { /* Not a temp var */
+               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 (EG(active_op_array)->return_reference == ZEND_RETURN_REF ||
                            (PZVAL_IS_REF(retval_ptr) && Z_REFCOUNT_P(retval_ptr) > 0)) {
                                zval *ret;
@@ -3115,7 +3119,7 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMP|VAR|CV, ANY)
                zval *saved_object;
                zend_function *saved_function;
 
-               EG(return_value_ptr_ptr) = EX_T(opline->result.u.var).var.ptr_ptr;
+               EG(return_value_ptr_ptr) = return_value_used ? EX_T(opline->result.u.var).var.ptr_ptr : NULL;
                EG(active_op_array) = new_op_array;
                EX_T(opline->result.u.var).var.ptr = NULL;
 
@@ -3130,11 +3134,7 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMP|VAR|CV, ANY)
                EX(function_state).function = saved_function;
                EX(object) = saved_object;
 
-               if (!return_value_used) {
-                       if (EX_T(opline->result.u.var).var.ptr) {
-                               zval_ptr_dtor(&EX_T(opline->result.u.var).var.ptr);
-                       }
-               } else { /* return value is used */
+               if (return_value_used) {
                        if (!EX_T(opline->result.u.var).var.ptr) { /* there was no return statement */
                                ALLOC_ZVAL(EX_T(opline->result.u.var).var.ptr);
                                INIT_PZVAL(EX_T(opline->result.u.var).var.ptr);
index 8c5223cc47b001219788fe9bc8e0619f6d32eafb..69688177d70c02bbf462f6b24053f0df753e5adc 100644 (file)
@@ -214,7 +214,7 @@ static int zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS)
                        zend_hash_init(EG(active_symbol_table), 0, NULL, ZVAL_PTR_DTOR, 0);
                        /*printf("Cache miss!  Initialized %x\n", EG(active_symbol_table));*/
                }
-               EG(return_value_ptr_ptr) = &EX_T(opline->result.u.var).var.ptr;
+               EG(return_value_ptr_ptr) = RETURN_VALUE_USED(opline) ? &EX_T(opline->result.u.var).var.ptr : NULL;
                EG(active_op_array) = (zend_op_array *) EX(function_state).function;
 
                zend_execute(EG(active_op_array) TSRMLS_CC);
@@ -224,8 +224,6 @@ static int zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS)
                        if (!EX_T(opline->result.u.var).var.ptr && !EG(exception)) {
                                ALLOC_INIT_ZVAL(EX_T(opline->result.u.var).var.ptr);
                        }
-               } else if (EX_T(opline->result.u.var).var.ptr) {
-                       zval_ptr_dtor(&EX_T(opline->result.u.var).var.ptr);
                }
 
                EG(opline_ptr) = &EX(opline);
@@ -1445,16 +1443,22 @@ static int ZEND_RETURN_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                        }
                }
 
-               SEPARATE_ZVAL_TO_MAKE_IS_REF(retval_ptr_ptr);
-               Z_ADDREF_PP(retval_ptr_ptr);
+               if (EG(return_value_ptr_ptr)) {
+                       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);
+               }
        } else {
 return_by_value:
 
                retval_ptr = &opline->op1.u.constant;
 
-               if (!0) { /* Not a temp var */
+               if (!EG(return_value_ptr_ptr)) {
+                       if (IS_CONST == IS_TMP_VAR) {
+
+                       }
+               } else if (!0) { /* Not a temp var */
                        if (EG(active_op_array)->return_reference == ZEND_RETURN_REF ||
                            (PZVAL_IS_REF(retval_ptr) && Z_REFCOUNT_P(retval_ptr) > 0)) {
                                zval *ret;
@@ -1737,7 +1741,7 @@ static int ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                zval *saved_object;
                zend_function *saved_function;
 
-               EG(return_value_ptr_ptr) = EX_T(opline->result.u.var).var.ptr_ptr;
+               EG(return_value_ptr_ptr) = return_value_used ? EX_T(opline->result.u.var).var.ptr_ptr : NULL;
                EG(active_op_array) = new_op_array;
                EX_T(opline->result.u.var).var.ptr = NULL;
 
@@ -1752,11 +1756,7 @@ static int ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                EX(function_state).function = saved_function;
                EX(object) = saved_object;
 
-               if (!return_value_used) {
-                       if (EX_T(opline->result.u.var).var.ptr) {
-                               zval_ptr_dtor(&EX_T(opline->result.u.var).var.ptr);
-                       }
-               } else { /* return value is used */
+               if (return_value_used) {
                        if (!EX_T(opline->result.u.var).var.ptr) { /* there was no return statement */
                                ALLOC_ZVAL(EX_T(opline->result.u.var).var.ptr);
                                INIT_PZVAL(EX_T(opline->result.u.var).var.ptr);
@@ -4603,16 +4603,22 @@ static int ZEND_RETURN_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                        }
                }
 
-               SEPARATE_ZVAL_TO_MAKE_IS_REF(retval_ptr_ptr);
-               Z_ADDREF_PP(retval_ptr_ptr);
+               if (EG(return_value_ptr_ptr)) {
+                       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);
+               }
        } else {
 return_by_value:
 
                retval_ptr = _get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC);
 
-               if (!1) { /* Not a temp var */
+               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 (EG(active_op_array)->return_reference == ZEND_RETURN_REF ||
                            (PZVAL_IS_REF(retval_ptr) && Z_REFCOUNT_P(retval_ptr) > 0)) {
                                zval *ret;
@@ -4904,7 +4910,7 @@ static int ZEND_INCLUDE_OR_EVAL_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                zval *saved_object;
                zend_function *saved_function;
 
-               EG(return_value_ptr_ptr) = EX_T(opline->result.u.var).var.ptr_ptr;
+               EG(return_value_ptr_ptr) = return_value_used ? EX_T(opline->result.u.var).var.ptr_ptr : NULL;
                EG(active_op_array) = new_op_array;
                EX_T(opline->result.u.var).var.ptr = NULL;
 
@@ -4919,11 +4925,7 @@ static int ZEND_INCLUDE_OR_EVAL_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                EX(function_state).function = saved_function;
                EX(object) = saved_object;
 
-               if (!return_value_used) {
-                       if (EX_T(opline->result.u.var).var.ptr) {
-                               zval_ptr_dtor(&EX_T(opline->result.u.var).var.ptr);
-                       }
-               } else { /* return value is used */
+               if (return_value_used) {
                        if (!EX_T(opline->result.u.var).var.ptr) { /* there was no return statement */
                                ALLOC_ZVAL(EX_T(opline->result.u.var).var.ptr);
                                INIT_PZVAL(EX_T(opline->result.u.var).var.ptr);
@@ -7696,16 +7698,22 @@ static int ZEND_RETURN_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                        }
                }
 
-               SEPARATE_ZVAL_TO_MAKE_IS_REF(retval_ptr_ptr);
-               Z_ADDREF_PP(retval_ptr_ptr);
+               if (EG(return_value_ptr_ptr)) {
+                       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);
+               }
        } else {
 return_by_value:
 
                retval_ptr = _get_zval_ptr_var(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC);
 
-               if (!0) { /* Not a temp var */
+               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 (EG(active_op_array)->return_reference == ZEND_RETURN_REF ||
                            (PZVAL_IS_REF(retval_ptr) && Z_REFCOUNT_P(retval_ptr) > 0)) {
                                zval *ret;
@@ -8102,7 +8110,7 @@ static int ZEND_INCLUDE_OR_EVAL_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                zval *saved_object;
                zend_function *saved_function;
 
-               EG(return_value_ptr_ptr) = EX_T(opline->result.u.var).var.ptr_ptr;
+               EG(return_value_ptr_ptr) = return_value_used ? EX_T(opline->result.u.var).var.ptr_ptr : NULL;
                EG(active_op_array) = new_op_array;
                EX_T(opline->result.u.var).var.ptr = NULL;
 
@@ -8117,11 +8125,7 @@ static int ZEND_INCLUDE_OR_EVAL_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                EX(function_state).function = saved_function;
                EX(object) = saved_object;
 
-               if (!return_value_used) {
-                       if (EX_T(opline->result.u.var).var.ptr) {
-                               zval_ptr_dtor(&EX_T(opline->result.u.var).var.ptr);
-                       }
-               } else { /* return value is used */
+               if (return_value_used) {
                        if (!EX_T(opline->result.u.var).var.ptr) { /* there was no return statement */
                                ALLOC_ZVAL(EX_T(opline->result.u.var).var.ptr);
                                INIT_PZVAL(EX_T(opline->result.u.var).var.ptr);
@@ -21368,16 +21372,22 @@ static int ZEND_RETURN_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                        }
                }
 
-               SEPARATE_ZVAL_TO_MAKE_IS_REF(retval_ptr_ptr);
-               Z_ADDREF_PP(retval_ptr_ptr);
+               if (EG(return_value_ptr_ptr)) {
+                       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);
+               }
        } else {
 return_by_value:
 
                retval_ptr = _get_zval_ptr_cv(&opline->op1, EX(Ts), BP_VAR_R TSRMLS_CC);
 
-               if (!0) { /* Not a temp var */
+               if (!EG(return_value_ptr_ptr)) {
+                       if (IS_CV == IS_TMP_VAR) {
+
+                       }
+               } else if (!0) { /* Not a temp var */
                        if (EG(active_op_array)->return_reference == ZEND_RETURN_REF ||
                            (PZVAL_IS_REF(retval_ptr) && Z_REFCOUNT_P(retval_ptr) > 0)) {
                                zval *ret;
@@ -21764,7 +21774,7 @@ static int ZEND_INCLUDE_OR_EVAL_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                zval *saved_object;
                zend_function *saved_function;
 
-               EG(return_value_ptr_ptr) = EX_T(opline->result.u.var).var.ptr_ptr;
+               EG(return_value_ptr_ptr) = return_value_used ? EX_T(opline->result.u.var).var.ptr_ptr : NULL;
                EG(active_op_array) = new_op_array;
                EX_T(opline->result.u.var).var.ptr = NULL;
 
@@ -21779,11 +21789,7 @@ static int ZEND_INCLUDE_OR_EVAL_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                EX(function_state).function = saved_function;
                EX(object) = saved_object;
 
-               if (!return_value_used) {
-                       if (EX_T(opline->result.u.var).var.ptr) {
-                               zval_ptr_dtor(&EX_T(opline->result.u.var).var.ptr);
-                       }
-               } else { /* return value is used */
+               if (return_value_used) {
                        if (!EX_T(opline->result.u.var).var.ptr) { /* there was no return statement */
                                ALLOC_ZVAL(EX_T(opline->result.u.var).var.ptr);
                                INIT_PZVAL(EX_T(opline->result.u.var).var.ptr);