From: Dmitry Stogov Date: Tue, 12 May 2015 12:56:42 +0000 (+0300) Subject: Mark first call frames of stack segment with ZEND_CALL_ALLOCATED flag to simplify... X-Git-Tag: PRE_PHP7_NSAPI_REMOVAL~42^2~101 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0586702d328ab33a46f641d88def2c5ceb792ca7;p=php Mark first call frames of stack segment with ZEND_CALL_ALLOCATED flag to simplify checks on stack deallocation. --- diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 8c1e49df3d..2027bfdfd2 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -455,6 +455,7 @@ struct _zend_execute_data { #define ZEND_CALL_CTOR_RESULT_UNUSED (1 << 4) #define ZEND_CALL_CLOSURE (1 << 5) #define ZEND_CALL_RELEASE_THIS (1 << 6) +#define ZEND_CALL_ALLOCATED (1 << 7) #define ZEND_CALL_INFO(call) \ (Z_TYPE_INFO((call)->This) >> 24) diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 26415b0d7c..f523b279bb 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -2077,7 +2077,7 @@ ZEND_API zend_execute_data *zend_create_generator_execute_data(zend_execute_data EG(vm_stack_top) = EG(vm_stack)->top; EG(vm_stack_end) = EG(vm_stack)->end; - call_info = ZEND_CALL_TOP_FUNCTION | (ZEND_CALL_INFO(call) & (ZEND_CALL_CLOSURE|ZEND_CALL_RELEASE_THIS)); + call_info = ZEND_CALL_TOP_FUNCTION | ZEND_CALL_ALLOCATED | (ZEND_CALL_INFO(call) & (ZEND_CALL_CLOSURE|ZEND_CALL_RELEASE_THIS)); if (Z_OBJ(call->This)) { call_info |= ZEND_CALL_RELEASE_THIS; } diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 312a6eb447..75d61ded53 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -153,24 +153,19 @@ ZEND_API void zend_vm_stack_init(void); ZEND_API void zend_vm_stack_destroy(void); ZEND_API void* zend_vm_stack_extend(size_t size); -static zend_always_inline zval* zend_vm_stack_alloc(size_t size) -{ - char *top = (char*)EG(vm_stack_top); - - if (UNEXPECTED(size > (size_t)(((char*)EG(vm_stack_end)) - top))) { - return (zval*)zend_vm_stack_extend(size); - } - EG(vm_stack_top) = (zval*)(top + size); - return (zval*)top; -} - static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame_ex(uint32_t used_stack, uint32_t call_info, zend_function *func, uint32_t num_args, zend_class_entry *called_scope, zend_object *object) { - zend_execute_data *call = (zend_execute_data*)zend_vm_stack_alloc(used_stack); + zend_execute_data *call = (zend_execute_data*)EG(vm_stack_top); + if (UNEXPECTED(used_stack > (size_t)(((char*)EG(vm_stack_end)) - (char*)call))) { + call = (zend_execute_data*)zend_vm_stack_extend(used_stack); + ZEND_SET_CALL_INFO(call, call_info | ZEND_CALL_ALLOCATED); + } else { + EG(vm_stack_top) = (zval*)((char*)call + used_stack); + ZEND_SET_CALL_INFO(call, call_info); + } call->func = func; Z_OBJ(call->This) = object; - ZEND_SET_CALL_INFO(call, call_info); ZEND_CALL_NUM_ARGS(call) = num_args; call->called_scope = called_scope; return call; @@ -240,10 +235,11 @@ static zend_always_inline void zend_vm_stack_free_args(zend_execute_data *call) } } -static zend_always_inline void zend_vm_stack_free_call_frame(zend_execute_data *call) +static zend_always_inline void zend_vm_stack_free_call_frame_ex(uint32_t call_info, zend_execute_data *call) { - zend_vm_stack p = EG(vm_stack); - if (UNEXPECTED(ZEND_VM_STACK_ELEMETS(p) == (zval*)call)) { + if (UNEXPECTED(call_info & ZEND_CALL_ALLOCATED)) { + zend_vm_stack p = EG(vm_stack); + zend_vm_stack prev = p->prev; EG(vm_stack_top) = prev->top; @@ -255,6 +251,11 @@ static zend_always_inline void zend_vm_stack_free_call_frame(zend_execute_data * } } +static zend_always_inline void zend_vm_stack_free_call_frame(zend_execute_data *call) +{ + zend_vm_stack_free_call_frame_ex(ZEND_CALL_INFO(call), call); +} + /* services */ ZEND_API const char *get_active_class_name(const char **space); ZEND_API const char *get_active_function_name(void); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 1c8afad058..eec2891ad7 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2395,7 +2395,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) if (UNEXPECTED(EX(symbol_table) != NULL)) { zend_clean_and_cache_symbol_table(EX(symbol_table)); } - zend_vm_stack_free_extra_args(execute_data); + zend_vm_stack_free_extra_args_ex(call_info, execute_data); old_execute_data = execute_data; execute_data = EG(current_execute_data) = EX(prev_execute_data); if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { @@ -2420,7 +2420,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) } EG(scope) = EX(func)->op_array.scope; - zend_vm_stack_free_call_frame(old_execute_data); + zend_vm_stack_free_call_frame_ex(call_info, old_execute_data); if (UNEXPECTED(EG(exception) != NULL)) { const zend_op *old_opline = EX(opline); @@ -2440,7 +2440,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) efree_size(EX(func), sizeof(zend_op_array)); old_execute_data = execute_data; execute_data = EG(current_execute_data) = EX(prev_execute_data); - zend_vm_stack_free_call_frame(old_execute_data); + zend_vm_stack_free_call_frame_ex(call_info, old_execute_data); zend_attach_symbol_table(execute_data); if (UNEXPECTED(EG(exception) != NULL)) { @@ -2457,7 +2457,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) if (UNEXPECTED(EX(symbol_table) != NULL)) { zend_clean_and_cache_symbol_table(EX(symbol_table)); } - zend_vm_stack_free_extra_args(execute_data); + zend_vm_stack_free_extra_args_ex(call_info, execute_data); EG(current_execute_data) = EX(prev_execute_data); if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { OBJ_RELEASE((zend_object*)EX(func)->op_array.prototype); @@ -2478,7 +2478,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) } EG(current_execute_data) = EX(prev_execute_data); } - zend_vm_stack_free_call_frame(execute_data); + zend_vm_stack_free_call_frame_ex(call_info, execute_data); ZEND_VM_RETURN(); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index a0e1825376..acb0151dd4 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -446,7 +446,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_ if (UNEXPECTED(EX(symbol_table) != NULL)) { zend_clean_and_cache_symbol_table(EX(symbol_table)); } - zend_vm_stack_free_extra_args(execute_data); + zend_vm_stack_free_extra_args_ex(call_info, execute_data); old_execute_data = execute_data; execute_data = EG(current_execute_data) = EX(prev_execute_data); if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { @@ -471,7 +471,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_ } EG(scope) = EX(func)->op_array.scope; - zend_vm_stack_free_call_frame(old_execute_data); + zend_vm_stack_free_call_frame_ex(call_info, old_execute_data); if (UNEXPECTED(EG(exception) != NULL)) { const zend_op *old_opline = EX(opline); @@ -491,7 +491,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_ efree_size(EX(func), sizeof(zend_op_array)); old_execute_data = execute_data; execute_data = EG(current_execute_data) = EX(prev_execute_data); - zend_vm_stack_free_call_frame(old_execute_data); + zend_vm_stack_free_call_frame_ex(call_info, old_execute_data); zend_attach_symbol_table(execute_data); if (UNEXPECTED(EG(exception) != NULL)) { @@ -508,7 +508,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_ if (UNEXPECTED(EX(symbol_table) != NULL)) { zend_clean_and_cache_symbol_table(EX(symbol_table)); } - zend_vm_stack_free_extra_args(execute_data); + zend_vm_stack_free_extra_args_ex(call_info, execute_data); EG(current_execute_data) = EX(prev_execute_data); if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { OBJ_RELEASE((zend_object*)EX(func)->op_array.prototype); @@ -529,7 +529,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_ } EG(current_execute_data) = EX(prev_execute_data); } - zend_vm_stack_free_call_frame(execute_data); + zend_vm_stack_free_call_frame_ex(call_info, execute_data); ZEND_VM_RETURN(); } @@ -2058,7 +2058,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_DYNAMIC_CALL_SPEC_CONST_H try_function_name: if (IS_CONST != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) { const char *colon; - + if ((colon = zend_memrchr(Z_STRVAL_P(function_name), ':', Z_STRLEN_P(function_name))) != NULL && colon > Z_STRVAL_P(function_name) && *(colon-1) == ':' @@ -2066,24 +2066,24 @@ try_function_name: zend_string *mname; size_t cname_length = colon - Z_STRVAL_P(function_name) - 1; size_t mname_length = Z_STRLEN_P(function_name) - cname_length - (sizeof("::") - 1); - + if (!mname_length) { zend_error(E_EXCEPTION | E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(function_name)); HANDLE_EXCEPTION(); } - + lcname = zend_string_init(Z_STRVAL_P(function_name), cname_length, 0); - + called_scope = zend_fetch_class_by_name(lcname, NULL, ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION); if (UNEXPECTED(called_scope == NULL)) { zend_string_release(lcname); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } - + mname = zend_string_init(Z_STRVAL_P(function_name) + (cname_length + sizeof("::") - 1), mname_length, 0); - + if (called_scope->get_static_method) { fbc = called_scope->get_static_method(called_scope, mname); } else { @@ -2098,10 +2098,10 @@ try_function_name: HANDLE_EXCEPTION(); } - + zend_string_release(lcname); zend_string_release(mname); - + if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { zend_error(E_DEPRECATED, @@ -2135,6 +2135,7 @@ try_function_name: called_scope = NULL; object = NULL; } + } else if (IS_CONST != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) && Z_OBJ_HANDLER_P(function_name, get_closure) && @@ -2529,7 +2530,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_DYNAMIC_CALL_SPEC_CV_HAND try_function_name: if (IS_CV != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) { const char *colon; - + if ((colon = zend_memrchr(Z_STRVAL_P(function_name), ':', Z_STRLEN_P(function_name))) != NULL && colon > Z_STRVAL_P(function_name) && *(colon-1) == ':' @@ -2537,24 +2538,24 @@ try_function_name: zend_string *mname; size_t cname_length = colon - Z_STRVAL_P(function_name) - 1; size_t mname_length = Z_STRLEN_P(function_name) - cname_length - (sizeof("::") - 1); - + if (!mname_length) { zend_error(E_EXCEPTION | E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(function_name)); HANDLE_EXCEPTION(); } - + lcname = zend_string_init(Z_STRVAL_P(function_name), cname_length, 0); - + called_scope = zend_fetch_class_by_name(lcname, NULL, ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION); if (UNEXPECTED(called_scope == NULL)) { zend_string_release(lcname); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } - + mname = zend_string_init(Z_STRVAL_P(function_name) + (cname_length + sizeof("::") - 1), mname_length, 0); - + if (called_scope->get_static_method) { fbc = called_scope->get_static_method(called_scope, mname); } else { @@ -2569,10 +2570,10 @@ try_function_name: HANDLE_EXCEPTION(); } - + zend_string_release(lcname); zend_string_release(mname); - + if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { zend_error(E_DEPRECATED, @@ -2606,6 +2607,7 @@ try_function_name: called_scope = NULL; object = NULL; } + } else if (IS_CV != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) && Z_OBJ_HANDLER_P(function_name, get_closure) && @@ -2781,7 +2783,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_DYNAMIC_CALL_SPEC_TMPVAR_ try_function_name: if ((IS_TMP_VAR|IS_VAR) != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) { const char *colon; - + if ((colon = zend_memrchr(Z_STRVAL_P(function_name), ':', Z_STRLEN_P(function_name))) != NULL && colon > Z_STRVAL_P(function_name) && *(colon-1) == ':' @@ -2789,24 +2791,24 @@ try_function_name: zend_string *mname; size_t cname_length = colon - Z_STRVAL_P(function_name) - 1; size_t mname_length = Z_STRLEN_P(function_name) - cname_length - (sizeof("::") - 1); - + if (!mname_length) { zend_error(E_EXCEPTION | E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(function_name)); zval_ptr_dtor_nogc(free_op2); HANDLE_EXCEPTION(); } - + lcname = zend_string_init(Z_STRVAL_P(function_name), cname_length, 0); - + called_scope = zend_fetch_class_by_name(lcname, NULL, ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION); if (UNEXPECTED(called_scope == NULL)) { zend_string_release(lcname); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } - + mname = zend_string_init(Z_STRVAL_P(function_name) + (cname_length + sizeof("::") - 1), mname_length, 0); - + if (called_scope->get_static_method) { fbc = called_scope->get_static_method(called_scope, mname); } else { @@ -2821,10 +2823,10 @@ try_function_name: zval_ptr_dtor_nogc(free_op2); HANDLE_EXCEPTION(); } - + zend_string_release(lcname); zend_string_release(mname); - + if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { zend_error(E_DEPRECATED,