From: Dmitry Stogov Date: Tue, 5 Dec 2017 23:53:30 +0000 (+0300) Subject: Optimization of init_func_execute_data() X-Git-Tag: php-7.3.0alpha1~874 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d1d1aff4e54a014d3d3693fe4505517226402eea;p=php Optimization of init_func_execute_data() --- diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 53ed1ac2a5..a68e7d12ab 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -2150,12 +2150,70 @@ ZEND_API void zend_free_compiled_variables(zend_execute_data *execute_data) /* { * +----------------------------------------+ */ -static zend_always_inline void i_init_func_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value) /* {{{ */ +static zend_never_inline void zend_copy_extra_args(EXECUTE_DATA_D) +{ + zend_op_array *op_array = &EX(func)->op_array; + uint32_t first_extra_arg = op_array->num_args; + uint32_t num_args = EX_NUM_ARGS(); + zval *src; + size_t delta; + uint32_t count; + uint32_t type_flags = 0; + + if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) { + /* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */ +#if defined(ZEND_VM_FP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)) + opline += first_extra_arg; +#else + EX(opline) += first_extra_arg; +#endif + + } + + /* move extra args into separate array after all CV and TMP vars */ + src = EX_VAR_NUM(num_args - 1); + delta = op_array->last_var + op_array->T - first_extra_arg; + count = num_args - first_extra_arg; + if (EXPECTED(delta != 0)) { + delta *= sizeof(zval); + do { + type_flags |= Z_TYPE_INFO_P(src); + ZVAL_COPY_VALUE((zval*)(((char*)src) + delta), src); + ZVAL_UNDEF(src); + src--; + } while (--count); + } else { + do { + type_flags |= Z_TYPE_INFO_P(src); + src--; + } while (--count); + } + ZEND_ADD_CALL_FLAG(execute_data, ((type_flags >> Z_TYPE_FLAGS_SHIFT) & IS_TYPE_REFCOUNTED)); +} + +static zend_always_inline void zend_init_cvs(uint32_t first, uint32_t last EXECUTE_DATA_DC) +{ + if (EXPECTED(first < last)) { + zval *var = EX_VAR_NUM(first); + zval *end = EX_VAR_NUM(last); + + do { + ZVAL_UNDEF(var); + var++; + } while (var != end); + } +} + +static zend_always_inline void i_init_func_execute_data(zend_op_array *op_array, zval *return_value, zend_bool may_be_trampoline EXECUTE_DATA_DC) /* {{{ */ { uint32_t first_extra_arg, num_args; ZEND_ASSERT(EX(func) == (zend_function*)op_array); +#if defined(ZEND_VM_FP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)) + opline = op_array->opcodes; +#else EX(opline) = op_array->opcodes; +#endif EX(call) = NULL; EX(return_value) = return_value; @@ -2163,54 +2221,27 @@ static zend_always_inline void i_init_func_execute_data(zend_execute_data *execu first_extra_arg = op_array->num_args; num_args = EX_NUM_ARGS(); if (UNEXPECTED(num_args > first_extra_arg)) { - if (EXPECTED(!(op_array->fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))) { - zval *end, *src, *dst; - uint32_t type_flags = 0; - - if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) { - /* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */ - EX(opline) += first_extra_arg; - } - - /* move extra args into separate array after all CV and TMP vars */ - end = EX_VAR_NUM(first_extra_arg - 1); - src = end + (num_args - first_extra_arg); - dst = src + (op_array->last_var + op_array->T - first_extra_arg); - if (EXPECTED(src != dst)) { - do { - type_flags |= Z_TYPE_INFO_P(src); - ZVAL_COPY_VALUE(dst, src); - ZVAL_UNDEF(src); - src--; - dst--; - } while (src != end); - } else { - do { - type_flags |= Z_TYPE_INFO_P(src); - src--; - } while (src != end); - } - ZEND_ADD_CALL_FLAG(execute_data, ((type_flags >> Z_TYPE_FLAGS_SHIFT) & IS_TYPE_REFCOUNTED)); + if (!may_be_trampoline || EXPECTED(!(op_array->fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))) { + zend_copy_extra_args(EXECUTE_DATA_C); } } else if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) { /* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */ +#if defined(ZEND_VM_FP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)) + opline += num_args; +#else EX(opline) += num_args; +#endif } /* Initialize CV variables (skip arguments) */ - if (EXPECTED((int)num_args < op_array->last_var)) { - zval *var = EX_VAR_NUM(num_args); - zval *end = EX_VAR_NUM(op_array->last_var); - - do { - ZVAL_UNDEF(var); - var++; - } while (var != end); - } + zend_init_cvs(num_args, op_array->last_var EXECUTE_DATA_CC); EX_LOAD_RUN_TIME_CACHE(op_array); EG(current_execute_data) = execute_data; +#if defined(ZEND_VM_FP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)) + EX(opline) = opline; +#endif } /* }}} */ @@ -2242,14 +2273,28 @@ static zend_always_inline void i_init_code_execute_data(zend_execute_data *execu } /* }}} */ -ZEND_API void zend_init_func_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value) /* {{{ */ +ZEND_API void zend_init_func_execute_data(zend_execute_data *ex, zend_op_array *op_array, zval *return_value) /* {{{ */ { +#if defined(ZEND_VM_FP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)) + zend_execute_data *orig_execute_data = execute_data; + const zend_op *orig_opline = opline; + execute_data = ex; +#else + zend_execute_data *execute_data = ex; +#endif + EX(prev_execute_data) = EG(current_execute_data); if (!op_array->run_time_cache) { op_array->run_time_cache = zend_arena_alloc(&CG(arena), op_array->cache_size); memset(op_array->run_time_cache, 0, op_array->cache_size); } - i_init_func_execute_data(execute_data, op_array, return_value); + i_init_func_execute_data(op_array, return_value, 1 EXECUTE_DATA_CC); + +#if defined(ZEND_VM_FP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)) + EX(opline) = opline; + opline = orig_opline; + execute_data = orig_execute_data; +#endif } /* }}} */ diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index fe6c3109ce..3f5f2dc21c 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -3556,9 +3556,11 @@ ZEND_VM_HOT_HANDLER(130, ZEND_DO_UCALL, ANY, ANY, SPEC(RETVAL)) } call->prev_execute_data = execute_data; - i_init_func_execute_data(call, &fbc->op_array, ret); + execute_data = call; + i_init_func_execute_data(&fbc->op_array, ret, 0 EXECUTE_DATA_CC); + LOAD_OPLINE(); - ZEND_VM_ENTER(); + ZEND_VM_ENTER_EX(); } ZEND_VM_HOT_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL)) @@ -3579,9 +3581,11 @@ ZEND_VM_HOT_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL)) } call->prev_execute_data = execute_data; - i_init_func_execute_data(call, &fbc->op_array, ret); + execute_data = call; + i_init_func_execute_data(&fbc->op_array, ret, 0 EXECUTE_DATA_CC); + LOAD_OPLINE(); - ZEND_VM_ENTER(); + ZEND_VM_ENTER_EX(); } else { zval retval; ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION); @@ -3675,11 +3679,15 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL)) } call->prev_execute_data = execute_data; - i_init_func_execute_data(call, &fbc->op_array, ret); + execute_data = call; + i_init_func_execute_data(&fbc->op_array, ret, 1 EXECUTE_DATA_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { - ZEND_VM_ENTER(); + LOAD_OPLINE(); + ZEND_VM_ENTER_EX(); } else { + execute_data = EX(prev_execute_data); + LOAD_OPLINE(); ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP); zend_execute_ex(call); } @@ -7834,10 +7842,14 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY) if (UNEXPECTED(!fbc->op_array.run_time_cache)) { init_func_run_time_cache(&fbc->op_array); } - i_init_func_execute_data(call, &fbc->op_array, ret); + execute_data = call; + i_init_func_execute_data(&fbc->op_array, ret, 0 EXECUTE_DATA_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { - ZEND_VM_ENTER(); + LOAD_OPLINE(); + ZEND_VM_ENTER_EX(); } else { + execute_data = EX(prev_execute_data); + LOAD_OPLINE(); ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP); zend_execute_ex(call); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index a2350823c1..1aa04cab8e 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -400,12 +400,15 @@ typedef ZEND_OPCODE_HANDLER_RET (ZEND_FASTCALL *opcode_handler_t) (ZEND_OPCODE_H #define HANDLE_EXCEPTION() LOAD_OPLINE(); ZEND_VM_CONTINUE() #define HANDLE_EXCEPTION_LEAVE() LOAD_OPLINE(); ZEND_VM_LEAVE() #if defined(ZEND_VM_FP_GLOBAL_REG) -# define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_INTERRUPT_CHECK(); ZEND_VM_CONTINUE() +# define ZEND_VM_ENTER_EX() ZEND_VM_INTERRUPT_CHECK(); ZEND_VM_CONTINUE() +# define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_ENTER_EX() # define ZEND_VM_LEAVE() ZEND_VM_CONTINUE() #elif defined(ZEND_VM_IP_GLOBAL_REG) -# define ZEND_VM_ENTER() opline = EG(current_execute_data)->opline; return 1 +# define ZEND_VM_ENTER_EX() return 1 +# define ZEND_VM_ENTER() opline = EG(current_execute_data)->opline; ZEND_VM_ENTER_EX() # define ZEND_VM_LEAVE() return 2 #else +# define ZEND_VM_ENTER_EX() return 1 # define ZEND_VM_ENTER() return 1 # define ZEND_VM_LEAVE() return 2 #endif @@ -660,9 +663,11 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_UCALL_SPEC_RETV } call->prev_execute_data = execute_data; - i_init_func_execute_data(call, &fbc->op_array, ret); + execute_data = call; + i_init_func_execute_data(&fbc->op_array, ret, 0 EXECUTE_DATA_CC); + LOAD_OPLINE(); - ZEND_VM_ENTER(); + ZEND_VM_ENTER_EX(); } static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_UCALL_SPEC_RETVAL_USED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -682,9 +687,11 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_UCALL_SPEC_RETV } call->prev_execute_data = execute_data; - i_init_func_execute_data(call, &fbc->op_array, ret); + execute_data = call; + i_init_func_execute_data(&fbc->op_array, ret, 0 EXECUTE_DATA_CC); + LOAD_OPLINE(); - ZEND_VM_ENTER(); + ZEND_VM_ENTER_EX(); } static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -705,9 +712,11 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_S } call->prev_execute_data = execute_data; - i_init_func_execute_data(call, &fbc->op_array, ret); + execute_data = call; + i_init_func_execute_data(&fbc->op_array, ret, 0 EXECUTE_DATA_CC); + LOAD_OPLINE(); - ZEND_VM_ENTER(); + ZEND_VM_ENTER_EX(); } else { zval retval; ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION); @@ -783,9 +792,11 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_S } call->prev_execute_data = execute_data; - i_init_func_execute_data(call, &fbc->op_array, ret); + execute_data = call; + i_init_func_execute_data(&fbc->op_array, ret, 0 EXECUTE_DATA_CC); + LOAD_OPLINE(); - ZEND_VM_ENTER(); + ZEND_VM_ENTER_EX(); } else { zval retval; ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION); @@ -879,11 +890,15 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV } call->prev_execute_data = execute_data; - i_init_func_execute_data(call, &fbc->op_array, ret); + execute_data = call; + i_init_func_execute_data(&fbc->op_array, ret, 1 EXECUTE_DATA_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { - ZEND_VM_ENTER(); + LOAD_OPLINE(); + ZEND_VM_ENTER_EX(); } else { + execute_data = EX(prev_execute_data); + LOAD_OPLINE(); ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP); zend_execute_ex(call); } @@ -1002,11 +1017,15 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV } call->prev_execute_data = execute_data; - i_init_func_execute_data(call, &fbc->op_array, ret); + execute_data = call; + i_init_func_execute_data(&fbc->op_array, ret, 1 EXECUTE_DATA_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { - ZEND_VM_ENTER(); + LOAD_OPLINE(); + ZEND_VM_ENTER_EX(); } else { + execute_data = EX(prev_execute_data); + LOAD_OPLINE(); ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP); zend_execute_ex(call); } @@ -2000,10 +2019,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_HANDLER(Z if (UNEXPECTED(!fbc->op_array.run_time_cache)) { init_func_run_time_cache(&fbc->op_array); } - i_init_func_execute_data(call, &fbc->op_array, ret); + execute_data = call; + i_init_func_execute_data(&fbc->op_array, ret, 0 EXECUTE_DATA_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { - ZEND_VM_ENTER(); + LOAD_OPLINE(); + ZEND_VM_ENTER_EX(); } else { + execute_data = EX(prev_execute_data); + LOAD_OPLINE(); ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP); zend_execute_ex(call); } diff --git a/Zend/zend_vm_gen.php b/Zend/zend_vm_gen.php index 7610da49e7..996cacf9e2 100644 --- a/Zend/zend_vm_gen.php +++ b/Zend/zend_vm_gen.php @@ -1675,12 +1675,15 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"#define HANDLE_EXCEPTION() LOAD_OPLINE(); ZEND_VM_CONTINUE()\n"); out($f,"#define HANDLE_EXCEPTION_LEAVE() LOAD_OPLINE(); ZEND_VM_LEAVE()\n"); out($f,"#if defined(ZEND_VM_FP_GLOBAL_REG)\n"); - out($f,"# define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_INTERRUPT_CHECK(); ZEND_VM_CONTINUE()\n"); + out($f,"# define ZEND_VM_ENTER_EX() ZEND_VM_INTERRUPT_CHECK(); ZEND_VM_CONTINUE()\n"); + out($f,"# define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_ENTER_EX()\n"); out($f,"# define ZEND_VM_LEAVE() ZEND_VM_CONTINUE()\n"); out($f,"#elif defined(ZEND_VM_IP_GLOBAL_REG)\n"); - out($f,"# define ZEND_VM_ENTER() opline = EG(current_execute_data)->opline; return 1\n"); + out($f,"# define ZEND_VM_ENTER_EX() return 1\n"); + out($f,"# define ZEND_VM_ENTER() opline = EG(current_execute_data)->opline; ZEND_VM_ENTER_EX()\n"); out($f,"# define ZEND_VM_LEAVE() return 2\n"); out($f,"#else\n"); + out($f,"# define ZEND_VM_ENTER_EX() return 1\n"); out($f,"# define ZEND_VM_ENTER() return 1\n"); out($f,"# define ZEND_VM_LEAVE() return 2\n"); out($f,"#endif\n"); @@ -1719,7 +1722,8 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"#define HANDLE_EXCEPTION_LEAVE() LOAD_OPLINE(); ZEND_VM_LEAVE()\n"); out($f,"#define ZEND_VM_CONTINUE() goto zend_vm_continue\n"); out($f,"#define ZEND_VM_RETURN() return\n"); - out($f,"#define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_INTERRUPT_CHECK(); ZEND_VM_CONTINUE()\n"); + out($f,"#define ZEND_VM_ENTER_EX() ZEND_VM_INTERRUPT_CHECK(); ZEND_VM_CONTINUE()\n"); + out($f,"#define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_ENTER_EX()\n"); out($f,"#define ZEND_VM_LEAVE() ZEND_VM_CONTINUE()\n"); out($f,"#define ZEND_VM_INTERRUPT() goto zend_interrupt_helper".($spec?"_SPEC":"").";\n"); out($f,"#define ZEND_VM_LOOP_INTERRUPT() goto zend_interrupt_helper".($spec?"_SPEC":"").";\n"); @@ -1755,7 +1759,8 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) } out($f,"#define ZEND_VM_CONTINUE() goto *(void**)(OPLINE->handler)\n"); out($f,"#define ZEND_VM_RETURN() return\n"); - out($f,"#define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_INTERRUPT_CHECK(); ZEND_VM_CONTINUE()\n"); + out($f,"#define ZEND_VM_ENTER_EX() ZEND_VM_INTERRUPT_CHECK(); ZEND_VM_CONTINUE()\n"); + out($f,"#define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_ENTER_EX()\n"); out($f,"#define ZEND_VM_LEAVE() ZEND_VM_CONTINUE()\n"); out($f,"#define ZEND_VM_INTERRUPT() goto zend_interrupt_helper".($spec?"_SPEC":"").";\n"); out($f,"#define ZEND_VM_LOOP_INTERRUPT() goto zend_interrupt_helper".($spec?"_SPEC":"").";\n"); @@ -2658,11 +2663,13 @@ function gen_vm($def, $skel) { out($f,"#define HANDLE_EXCEPTION_LEAVE() LOAD_OPLINE(); ZEND_VM_LEAVE()\n"); out($f,"#undef ZEND_VM_CONTINUE\n"); out($f,"#undef ZEND_VM_RETURN\n"); + out($f,"#undef ZEND_VM_ENTER_EX\n"); out($f,"#undef ZEND_VM_ENTER\n"); out($f,"#undef ZEND_VM_LEAVE\n"); out($f,"#undef ZEND_VM_DISPATCH\n"); out($f,"#define ZEND_VM_CONTINUE() return 0\n"); out($f,"#define ZEND_VM_RETURN() return -1\n"); + out($f,"#define ZEND_VM_ENTER_EX() return 1\n"); out($f,"#define ZEND_VM_ENTER() return 1\n"); out($f,"#define ZEND_VM_LEAVE() return 2\n"); out($f,"#define ZEND_VM_INTERRUPT() return zend_interrupt_helper(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n");