From: Dmitry Stogov Date: Wed, 25 Feb 2015 07:37:21 +0000 (+0300) Subject: Added specialized versions of DO_FCALL handler: X-Git-Tag: PRE_PHP7_EREG_MYSQL_REMOVALS~71 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c2c78dc963a3360035dfaca417fa3351bd6c5e1f;p=php Added specialized versions of DO_FCALL handler: DO_ICALL - for internal functions DO_UCALL - for user functions DO_FCALL_BY_NAME - plain, most probably user, funcstions (not methods) --- diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 035a4c6c88..195d9c2509 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -2258,6 +2258,9 @@ ZEND_FUNCTION(debug_print_backtrace) skip->prev_execute_data->func && ZEND_USER_CODE(skip->prev_execute_data->func->common.type) && skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL && + skip->prev_execute_data->opline->opcode != ZEND_DO_ICALL && + skip->prev_execute_data->opline->opcode != ZEND_DO_UCALL && + skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL_BY_NAME && skip->prev_execute_data->opline->opcode != ZEND_INCLUDE_OR_EVAL) { skip = skip->prev_execute_data; } @@ -2453,6 +2456,9 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int skip->prev_execute_data->func && ZEND_USER_CODE(skip->prev_execute_data->func->common.type) && skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL && + skip->prev_execute_data->opline->opcode != ZEND_DO_ICALL && + skip->prev_execute_data->opline->opcode != ZEND_DO_UCALL && + skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL_BY_NAME && skip->prev_execute_data->opline->opcode != ZEND_INCLUDE_OR_EVAL) { skip = skip->prev_execute_data; } diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 9fbfa1f82f..1a71608083 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2617,6 +2617,31 @@ uint32_t zend_compile_args(zend_ast *ast, zend_function *fbc) /* {{{ */ } /* }}} */ +ZEND_API zend_uchar zend_get_call_op(zend_uchar init_op, zend_function *fbc) /* {{{ */ +{ + if (fbc) { + if (fbc->type == ZEND_INTERNAL_FUNCTION) { + if (!zend_execute_internal && + !fbc->common.scope && + !(fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED|ZEND_ACC_HAS_TYPE_HINTS))) { + return ZEND_DO_ICALL; + } + } else { + if (zend_execute_ex == execute_ex && + !(fbc->common.fn_flags & ZEND_ACC_GENERATOR)) { + return ZEND_DO_UCALL; + } + } + } else if (zend_execute_ex == execute_ex && + !zend_execute_internal && + (init_op == ZEND_INIT_FCALL_BY_NAME || + init_op == ZEND_INIT_NS_FCALL_BY_NAME)) { + return ZEND_DO_FCALL_BY_NAME; + } + return ZEND_DO_FCALL; +} +/* }}} */ + void zend_compile_call_common(znode *result, zend_ast *args_ast, zend_function *fbc) /* {{{ */ { zend_op *opline; @@ -2636,7 +2661,7 @@ void zend_compile_call_common(znode *result, zend_ast *args_ast, zend_function * } call_flags = (opline->opcode == ZEND_NEW ? ZEND_CALL_CTOR : 0); - opline = zend_emit_op(result, ZEND_DO_FCALL, NULL, NULL); + opline = zend_emit_op(result, zend_get_call_op(opline->opcode, fbc), NULL, NULL); opline->op1.num = call_flags; zend_do_extended_fcall_end(); diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 6073e240f3..8e4148795e 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -718,6 +718,7 @@ ZEND_API zend_bool zend_is_compiling(void); ZEND_API char *zend_make_compiled_string_description(const char *name); ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify_handlers); uint32_t zend_get_class_fetch_type(zend_string *name); +ZEND_API zend_uchar zend_get_call_op(zend_uchar init_op, zend_function *fbc); typedef zend_bool (*zend_auto_global_callback)(zend_string *name); typedef struct _zend_auto_global { diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index b016df1e25..0cf2f2c53e 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1742,7 +1742,7 @@ 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_always_inline void i_init_func_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value, int check_this) /* {{{ */ { uint32_t first_extra_arg, num_args; ZEND_ASSERT(EX(func) == (zend_function*)op_array); @@ -1798,7 +1798,7 @@ static zend_always_inline void i_init_func_execute_data(zend_execute_data *execu } while (var != end); } - if (op_array->this_var != (uint32_t)-1 && EXPECTED(Z_OBJ(EX(This)))) { + if (check_this && op_array->this_var != (uint32_t)-1 && EXPECTED(Z_OBJ(EX(This)))) { ZVAL_OBJ(EX_VAR(op_array->this_var), Z_OBJ(EX(This))); GC_REFCOUNT(Z_OBJ(EX(This)))++; } @@ -1966,7 +1966,7 @@ ZEND_API zend_execute_data *zend_create_generator_execute_data(zend_execute_data EX(symbol_table) = NULL; - i_init_func_execute_data(execute_data, op_array, return_value); + i_init_func_execute_data(execute_data, op_array, return_value, 1); return execute_data; } diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index fc94beeb7f..f52d9f33ce 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -691,7 +691,10 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / EG(current_execute_data) = &dummy_execute_data; } else if (EG(current_execute_data)->func && ZEND_USER_CODE(EG(current_execute_data)->func->common.type) && - EG(current_execute_data)->opline->opcode != ZEND_DO_FCALL) { + EG(current_execute_data)->opline->opcode != ZEND_DO_FCALL && + EG(current_execute_data)->opline->opcode != ZEND_DO_ICALL && + EG(current_execute_data)->opline->opcode != ZEND_DO_UCALL && + EG(current_execute_data)->opline->opcode != ZEND_DO_FCALL_BY_NAME) { /* Insert fake frame in case of include or magic calls */ dummy_execute_data = *EG(current_execute_data); dummy_execute_data.prev_execute_data = EG(current_execute_data); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 8e2051e6c0..04b1d1d696 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2354,7 +2354,10 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMPVAR|UNUSED|CV, CONST|TMPVAR|CV) opline->opcode == ZEND_NEW ) { nesting++; - } else if (opline->opcode == ZEND_DO_FCALL) { + } else if (opline->opcode == ZEND_DO_FCALL || + opline->opcode == ZEND_DO_ICALL || + opline->opcode == ZEND_DO_UCALL || + opline->opcode == ZEND_DO_FCALL_BY_NAME) { nesting--; } } while (nesting); @@ -2796,6 +2799,185 @@ ZEND_VM_HANDLER(61, ZEND_INIT_FCALL, ANY, CONST) ZEND_VM_NEXT_OPCODE(); } +ZEND_VM_HANDLER(129, ZEND_DO_ICALL, ANY, ANY) +{ + USE_OPLINE + zend_execute_data *call = EX(call); + zend_function *fbc = call->func; + zval *ret; + + SAVE_OPLINE(); + EX(call) = call->prev_execute_data; + + LOAD_OPLINE(); + + call->called_scope = EX(called_scope); + Z_OBJ(call->This) = Z_OBJ(EX(This)); + + call->prev_execute_data = execute_data; + EG(current_execute_data) = call; + + ret = EX_VAR(opline->result.var); + ZVAL_NULL(ret); + Z_VAR_FLAGS_P(ret) = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0 ? IS_VAR_RET_REF : 0; + + fbc->internal_function.handler(call, ret); + + ZEND_ASSERT( + !call->func || + !(call->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) || + zend_verify_internal_return_type(call->func, EX_VAR(opline->result.var))); + + EG(current_execute_data) = call->prev_execute_data; + zend_vm_stack_free_args(call); + zend_vm_stack_free_call_frame(call); + + if (!RETURN_VALUE_USED(opline)) { + zval_ptr_dtor(EX_VAR(opline->result.var)); + } + + if (UNEXPECTED(EG(exception) != NULL)) { + zend_throw_exception_internal(NULL); + if (RETURN_VALUE_USED(opline)) { + zval_ptr_dtor(EX_VAR(opline->result.var)); + } + HANDLE_EXCEPTION(); + } + + ZEND_VM_NEXT_OPCODE(); +} + +ZEND_VM_HANDLER(130, ZEND_DO_UCALL, ANY, ANY) +{ + USE_OPLINE + zend_execute_data *call = EX(call); + zend_function *fbc = call->func; + zval *ret; + + SAVE_OPLINE(); + EX(call) = call->prev_execute_data; + + LOAD_OPLINE(); + + EG(scope) = NULL; + ret = NULL; + call->symbol_table = NULL; + if (RETURN_VALUE_USED(opline)) { + ret = EX_VAR(opline->result.var); + ZVAL_NULL(ret); + Z_VAR_FLAGS_P(ret) = 0; + } + + call->prev_execute_data = execute_data; + i_init_func_execute_data(call, &fbc->op_array, ret, 0); + + ZEND_VM_ENTER(); +} + +ZEND_VM_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY) +{ + USE_OPLINE + zend_execute_data *call = EX(call); + zend_function *fbc = call->func; + zval *ret; + + SAVE_OPLINE(); + EX(call) = call->prev_execute_data; + + LOAD_OPLINE(); + + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { + EG(scope) = NULL; + if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_GENERATOR) != 0)) { + if (RETURN_VALUE_USED(opline)) { + zend_generator_create_zval(call, &fbc->op_array, EX_VAR(opline->result.var)); + } else { + zend_vm_stack_free_args(call); + } + + zend_vm_stack_free_call_frame(call); + } else { + ret = NULL; + call->symbol_table = NULL; + if (RETURN_VALUE_USED(opline)) { + ret = EX_VAR(opline->result.var); + ZVAL_NULL(ret); + Z_VAR_FLAGS_P(ret) = 0; + } + + call->prev_execute_data = execute_data; + i_init_func_execute_data(call, &fbc->op_array, ret, 0); + + ZEND_VM_ENTER(); + } + EG(scope) = EX(func)->op_array.scope; + } else { + ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION); + + if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) { + zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated", + fbc->common.scope ? fbc->common.scope->name->val : "", + fbc->common.scope ? "::" : "", + fbc->common.function_name->val); + if (UNEXPECTED(EG(exception) != NULL)) { + HANDLE_EXCEPTION(); + } + } + + call->called_scope = EX(called_scope); + Z_OBJ(call->This) = Z_OBJ(EX(This)); + + call->prev_execute_data = execute_data; + EG(current_execute_data) = call; + + if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) { + uint32_t i; + uint32_t num_args = ZEND_CALL_NUM_ARGS(call); + zval *p = ZEND_CALL_ARG(call, 1); + + for (i = 0; i < num_args; ++i) { + zend_verify_internal_arg_type(fbc, i + 1, p); + p++; + } + if (UNEXPECTED(EG(exception) != NULL)) { + EG(current_execute_data) = call->prev_execute_data; + zend_vm_stack_free_args(call); + zend_vm_stack_free_call_frame(call); + zend_throw_exception_internal(NULL); + HANDLE_EXCEPTION(); + } + } + + ret = EX_VAR(opline->result.var); + ZVAL_NULL(ret); + Z_VAR_FLAGS_P(ret) = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0 ? IS_VAR_RET_REF : 0; + + fbc->internal_function.handler(call, ret); + + ZEND_ASSERT( + !call->func || + !(call->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) || + zend_verify_internal_return_type(call->func, EX_VAR(opline->result.var))); + + EG(current_execute_data) = call->prev_execute_data; + zend_vm_stack_free_args(call); + zend_vm_stack_free_call_frame(call); + + if (!RETURN_VALUE_USED(opline)) { + zval_ptr_dtor(EX_VAR(opline->result.var)); + } + } + + if (UNEXPECTED(EG(exception) != NULL)) { + zend_throw_exception_internal(NULL); + if (RETURN_VALUE_USED(opline)) { + zval_ptr_dtor(EX_VAR(opline->result.var)); + } + HANDLE_EXCEPTION(); + } + ZEND_VM_NEXT_OPCODE(); +} + ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) { USE_OPLINE @@ -2843,7 +3025,7 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) } call->prev_execute_data = execute_data; - i_init_func_execute_data(call, &fbc->op_array, ret); + i_init_func_execute_data(call, &fbc->op_array, ret, 1); if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); @@ -2854,7 +3036,6 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) } } else if (EXPECTED(fbc->type < ZEND_USER_FUNCTION)) { int should_change_scope = 0; - zval *ret; if (fbc->common.scope) { should_change_scope = 1; @@ -5965,6 +6146,9 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) do { switch (opline->opcode) { case ZEND_DO_FCALL: + case ZEND_DO_ICALL: + case ZEND_DO_UCALL: + case ZEND_DO_FCALL_BY_NAME: level++; break; case ZEND_INIT_FCALL: @@ -6011,6 +6195,9 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) do { switch (opline->opcode) { case ZEND_DO_FCALL: + case ZEND_DO_ICALL: + case ZEND_DO_UCALL: + case ZEND_DO_FCALL_BY_NAME: level++; break; case ZEND_INIT_FCALL: diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 04a8787262..d4e29353fc 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -486,6 +486,185 @@ static int ZEND_FASTCALL ZEND_JMP_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_CONTINUE(); } +static int ZEND_FASTCALL ZEND_DO_ICALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_execute_data *call = EX(call); + zend_function *fbc = call->func; + zval *ret; + + SAVE_OPLINE(); + EX(call) = call->prev_execute_data; + + LOAD_OPLINE(); + + call->called_scope = EX(called_scope); + Z_OBJ(call->This) = Z_OBJ(EX(This)); + + call->prev_execute_data = execute_data; + EG(current_execute_data) = call; + + ret = EX_VAR(opline->result.var); + ZVAL_NULL(ret); + Z_VAR_FLAGS_P(ret) = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0 ? IS_VAR_RET_REF : 0; + + fbc->internal_function.handler(call, ret); + + ZEND_ASSERT( + !call->func || + !(call->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) || + zend_verify_internal_return_type(call->func, EX_VAR(opline->result.var))); + + EG(current_execute_data) = call->prev_execute_data; + zend_vm_stack_free_args(call); + zend_vm_stack_free_call_frame(call); + + if (!RETURN_VALUE_USED(opline)) { + zval_ptr_dtor(EX_VAR(opline->result.var)); + } + + if (UNEXPECTED(EG(exception) != NULL)) { + zend_throw_exception_internal(NULL); + if (RETURN_VALUE_USED(opline)) { + zval_ptr_dtor(EX_VAR(opline->result.var)); + } + HANDLE_EXCEPTION(); + } + + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_DO_UCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_execute_data *call = EX(call); + zend_function *fbc = call->func; + zval *ret; + + SAVE_OPLINE(); + EX(call) = call->prev_execute_data; + + LOAD_OPLINE(); + + EG(scope) = NULL; + ret = NULL; + call->symbol_table = NULL; + if (RETURN_VALUE_USED(opline)) { + ret = EX_VAR(opline->result.var); + ZVAL_NULL(ret); + Z_VAR_FLAGS_P(ret) = 0; + } + + call->prev_execute_data = execute_data; + i_init_func_execute_data(call, &fbc->op_array, ret, 0); + + ZEND_VM_ENTER(); +} + +static int ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_execute_data *call = EX(call); + zend_function *fbc = call->func; + zval *ret; + + SAVE_OPLINE(); + EX(call) = call->prev_execute_data; + + LOAD_OPLINE(); + + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { + EG(scope) = NULL; + if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_GENERATOR) != 0)) { + if (RETURN_VALUE_USED(opline)) { + zend_generator_create_zval(call, &fbc->op_array, EX_VAR(opline->result.var)); + } else { + zend_vm_stack_free_args(call); + } + + zend_vm_stack_free_call_frame(call); + } else { + ret = NULL; + call->symbol_table = NULL; + if (RETURN_VALUE_USED(opline)) { + ret = EX_VAR(opline->result.var); + ZVAL_NULL(ret); + Z_VAR_FLAGS_P(ret) = 0; + } + + call->prev_execute_data = execute_data; + i_init_func_execute_data(call, &fbc->op_array, ret, 0); + + ZEND_VM_ENTER(); + } + EG(scope) = EX(func)->op_array.scope; + } else { + ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION); + + if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) { + zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated", + fbc->common.scope ? fbc->common.scope->name->val : "", + fbc->common.scope ? "::" : "", + fbc->common.function_name->val); + if (UNEXPECTED(EG(exception) != NULL)) { + HANDLE_EXCEPTION(); + } + } + + call->called_scope = EX(called_scope); + Z_OBJ(call->This) = Z_OBJ(EX(This)); + + call->prev_execute_data = execute_data; + EG(current_execute_data) = call; + + if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) { + uint32_t i; + uint32_t num_args = ZEND_CALL_NUM_ARGS(call); + zval *p = ZEND_CALL_ARG(call, 1); + + for (i = 0; i < num_args; ++i) { + zend_verify_internal_arg_type(fbc, i + 1, p); + p++; + } + if (UNEXPECTED(EG(exception) != NULL)) { + EG(current_execute_data) = call->prev_execute_data; + zend_vm_stack_free_args(call); + zend_vm_stack_free_call_frame(call); + zend_throw_exception_internal(NULL); + HANDLE_EXCEPTION(); + } + } + + ret = EX_VAR(opline->result.var); + ZVAL_NULL(ret); + Z_VAR_FLAGS_P(ret) = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0 ? IS_VAR_RET_REF : 0; + + fbc->internal_function.handler(call, ret); + + ZEND_ASSERT( + !call->func || + !(call->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) || + zend_verify_internal_return_type(call->func, EX_VAR(opline->result.var))); + + EG(current_execute_data) = call->prev_execute_data; + zend_vm_stack_free_args(call); + zend_vm_stack_free_call_frame(call); + + if (!RETURN_VALUE_USED(opline)) { + zval_ptr_dtor(EX_VAR(opline->result.var)); + } + } + + if (UNEXPECTED(EG(exception) != NULL)) { + zend_throw_exception_internal(NULL); + if (RETURN_VALUE_USED(opline)) { + zval_ptr_dtor(EX_VAR(opline->result.var)); + } + HANDLE_EXCEPTION(); + } + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -533,7 +712,7 @@ static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } call->prev_execute_data = execute_data; - i_init_func_execute_data(call, &fbc->op_array, ret); + i_init_func_execute_data(call, &fbc->op_array, ret, 1); if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); @@ -544,7 +723,6 @@ static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } else if (EXPECTED(fbc->type < ZEND_USER_FUNCTION)) { int should_change_scope = 0; - zval *ret; if (fbc->common.scope) { should_change_scope = 1; @@ -1255,6 +1433,9 @@ static int ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER do { switch (opline->opcode) { case ZEND_DO_FCALL: + case ZEND_DO_ICALL: + case ZEND_DO_UCALL: + case ZEND_DO_FCALL_BY_NAME: level++; break; case ZEND_INIT_FCALL: @@ -1301,6 +1482,9 @@ static int ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER do { switch (opline->opcode) { case ZEND_DO_FCALL: + case ZEND_DO_ICALL: + case ZEND_DO_UCALL: + case ZEND_DO_FCALL_BY_NAME: level++; break; case ZEND_INIT_FCALL: @@ -19437,7 +19621,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CONST_HANDLER(ZEND_O opline->opcode == ZEND_NEW ) { nesting++; - } else if (opline->opcode == ZEND_DO_FCALL) { + } else if (opline->opcode == ZEND_DO_FCALL || + opline->opcode == ZEND_DO_ICALL || + opline->opcode == ZEND_DO_UCALL || + opline->opcode == ZEND_DO_FCALL_BY_NAME) { nesting--; } } while (nesting); @@ -21644,7 +21831,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CV_HANDLER(ZEND_OPCO opline->opcode == ZEND_NEW ) { nesting++; - } else if (opline->opcode == ZEND_DO_FCALL) { + } else if (opline->opcode == ZEND_DO_FCALL || + opline->opcode == ZEND_DO_ICALL || + opline->opcode == ZEND_DO_UCALL || + opline->opcode == ZEND_DO_FCALL_BY_NAME) { nesting--; } } while (nesting); @@ -23035,7 +23225,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_TMPVAR_HANDLER(ZEND_ opline->opcode == ZEND_NEW ) { nesting++; - } else if (opline->opcode == ZEND_DO_FCALL) { + } else if (opline->opcode == ZEND_DO_FCALL || + opline->opcode == ZEND_DO_ICALL || + opline->opcode == ZEND_DO_UCALL || + opline->opcode == ZEND_DO_FCALL_BY_NAME) { nesting--; } } while (nesting); @@ -26527,7 +26720,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CONST_HANDLER(ZEND_OPCOD opline->opcode == ZEND_NEW ) { nesting++; - } else if (opline->opcode == ZEND_DO_FCALL) { + } else if (opline->opcode == ZEND_DO_FCALL || + opline->opcode == ZEND_DO_ICALL || + opline->opcode == ZEND_DO_UCALL || + opline->opcode == ZEND_DO_FCALL_BY_NAME) { nesting--; } } while (nesting); @@ -30756,7 +30952,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HANDLER(ZEND_OPCODE_H opline->opcode == ZEND_NEW ) { nesting++; - } else if (opline->opcode == ZEND_DO_FCALL) { + } else if (opline->opcode == ZEND_DO_FCALL || + opline->opcode == ZEND_DO_ICALL || + opline->opcode == ZEND_DO_UCALL || + opline->opcode == ZEND_DO_FCALL_BY_NAME) { nesting--; } } while (nesting); @@ -32726,7 +32925,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_TMPVAR_HANDLER(ZEND_OPCO opline->opcode == ZEND_NEW ) { nesting++; - } else if (opline->opcode == ZEND_DO_FCALL) { + } else if (opline->opcode == ZEND_DO_FCALL || + opline->opcode == ZEND_DO_ICALL || + opline->opcode == ZEND_DO_UCALL || + opline->opcode == ZEND_DO_FCALL_BY_NAME) { nesting--; } } while (nesting); @@ -34399,7 +34601,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_CONST_HANDLER(ZEND_O opline->opcode == ZEND_NEW ) { nesting++; - } else if (opline->opcode == ZEND_DO_FCALL) { + } else if (opline->opcode == ZEND_DO_FCALL || + opline->opcode == ZEND_DO_ICALL || + opline->opcode == ZEND_DO_UCALL || + opline->opcode == ZEND_DO_FCALL_BY_NAME) { nesting--; } } while (nesting); @@ -36014,7 +36219,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_CV_HANDLER(ZEND_OPCO opline->opcode == ZEND_NEW ) { nesting++; - } else if (opline->opcode == ZEND_DO_FCALL) { + } else if (opline->opcode == ZEND_DO_FCALL || + opline->opcode == ZEND_DO_ICALL || + opline->opcode == ZEND_DO_UCALL || + opline->opcode == ZEND_DO_FCALL_BY_NAME) { nesting--; } } while (nesting); @@ -36674,7 +36882,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_TMPVAR_HANDLER(ZEND_ opline->opcode == ZEND_NEW ) { nesting++; - } else if (opline->opcode == ZEND_DO_FCALL) { + } else if (opline->opcode == ZEND_DO_FCALL || + opline->opcode == ZEND_DO_ICALL || + opline->opcode == ZEND_DO_UCALL || + opline->opcode == ZEND_DO_FCALL_BY_NAME) { nesting--; } } while (nesting); @@ -40155,81 +40366,81 @@ void zend_init_opcodes_handlers(void) ZEND_INIT_DYNAMIC_CALL_SPEC_TMPVAR_HANDLER, ZEND_NULL_HANDLER, ZEND_INIT_DYNAMIC_CALL_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_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_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_DO_ICALL_SPEC_HANDLER, + ZEND_DO_ICALL_SPEC_HANDLER, + ZEND_DO_ICALL_SPEC_HANDLER, + ZEND_DO_ICALL_SPEC_HANDLER, + ZEND_DO_ICALL_SPEC_HANDLER, + ZEND_DO_ICALL_SPEC_HANDLER, + ZEND_DO_ICALL_SPEC_HANDLER, + ZEND_DO_ICALL_SPEC_HANDLER, + ZEND_DO_ICALL_SPEC_HANDLER, + ZEND_DO_ICALL_SPEC_HANDLER, + ZEND_DO_ICALL_SPEC_HANDLER, + ZEND_DO_ICALL_SPEC_HANDLER, + ZEND_DO_ICALL_SPEC_HANDLER, + ZEND_DO_ICALL_SPEC_HANDLER, + ZEND_DO_ICALL_SPEC_HANDLER, + ZEND_DO_ICALL_SPEC_HANDLER, + ZEND_DO_ICALL_SPEC_HANDLER, + ZEND_DO_ICALL_SPEC_HANDLER, + ZEND_DO_ICALL_SPEC_HANDLER, + ZEND_DO_ICALL_SPEC_HANDLER, + ZEND_DO_ICALL_SPEC_HANDLER, + ZEND_DO_ICALL_SPEC_HANDLER, + ZEND_DO_ICALL_SPEC_HANDLER, + ZEND_DO_ICALL_SPEC_HANDLER, + ZEND_DO_ICALL_SPEC_HANDLER, + ZEND_DO_UCALL_SPEC_HANDLER, + ZEND_DO_UCALL_SPEC_HANDLER, + ZEND_DO_UCALL_SPEC_HANDLER, + ZEND_DO_UCALL_SPEC_HANDLER, + ZEND_DO_UCALL_SPEC_HANDLER, + ZEND_DO_UCALL_SPEC_HANDLER, + ZEND_DO_UCALL_SPEC_HANDLER, + ZEND_DO_UCALL_SPEC_HANDLER, + ZEND_DO_UCALL_SPEC_HANDLER, + ZEND_DO_UCALL_SPEC_HANDLER, + ZEND_DO_UCALL_SPEC_HANDLER, + ZEND_DO_UCALL_SPEC_HANDLER, + ZEND_DO_UCALL_SPEC_HANDLER, + ZEND_DO_UCALL_SPEC_HANDLER, + ZEND_DO_UCALL_SPEC_HANDLER, + ZEND_DO_UCALL_SPEC_HANDLER, + ZEND_DO_UCALL_SPEC_HANDLER, + ZEND_DO_UCALL_SPEC_HANDLER, + ZEND_DO_UCALL_SPEC_HANDLER, + ZEND_DO_UCALL_SPEC_HANDLER, + ZEND_DO_UCALL_SPEC_HANDLER, + ZEND_DO_UCALL_SPEC_HANDLER, + ZEND_DO_UCALL_SPEC_HANDLER, + ZEND_DO_UCALL_SPEC_HANDLER, + ZEND_DO_UCALL_SPEC_HANDLER, + ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, + ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, + ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, + ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, + ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, + ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, + ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, + ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, + ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, + ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, + ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, + ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, + ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, + ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, + ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, + ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, + ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, + ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, + ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, + ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, + ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, + ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, + ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, + ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, + ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c index 1ab2a9e0fa..991e56bc77 100644 --- a/Zend/zend_vm_opcodes.c +++ b/Zend/zend_vm_opcodes.c @@ -151,9 +151,9 @@ const char *zend_vm_opcodes_map[171] = { "ZEND_FE_FETCH_RW", "ZEND_FE_FREE", "ZEND_INIT_DYNAMIC_CALL", - NULL, - NULL, - NULL, + "ZEND_DO_ICALL", + "ZEND_DO_UCALL", + "ZEND_DO_FCALL_BY_NAME", "ZEND_PRE_INC_OBJ", "ZEND_PRE_DEC_OBJ", "ZEND_POST_INC_OBJ", diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h index d21ff08e7f..367e52150c 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -153,6 +153,9 @@ END_EXTERN_C() #define ZEND_FE_FETCH_RW 126 #define ZEND_FE_FREE 127 #define ZEND_INIT_DYNAMIC_CALL 128 +#define ZEND_DO_ICALL 129 +#define ZEND_DO_UCALL 130 +#define ZEND_DO_FCALL_BY_NAME 131 #define ZEND_PRE_INC_OBJ 132 #define ZEND_PRE_DEC_OBJ 133 #define ZEND_POST_INC_OBJ 134 diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c index 4db48944e1..0922d6e809 100644 --- a/ext/opcache/Optimizer/block_pass.c +++ b/ext/opcache/Optimizer/block_pass.c @@ -1828,6 +1828,9 @@ static void zend_t_usage(zend_code_block *block, zend_op_array *op_array, char * case ZEND_ASSIGN: case ZEND_ASSIGN_REF: case ZEND_DO_FCALL: + case ZEND_DO_ICALL: + case ZEND_DO_UCALL: + case ZEND_DO_FCALL_BY_NAME: if (ZEND_RESULT_TYPE(opline) == IS_VAR) { ZEND_RESULT_TYPE(opline) |= EXT_TYPE_UNUSED; } diff --git a/ext/opcache/Optimizer/optimize_func_calls.c b/ext/opcache/Optimizer/optimize_func_calls.c index a83adab5ec..270e38d594 100644 --- a/ext/opcache/Optimizer/optimize_func_calls.c +++ b/ext/opcache/Optimizer/optimize_func_calls.c @@ -75,6 +75,9 @@ void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx) call++; break; case ZEND_DO_FCALL: + case ZEND_DO_ICALL: + case ZEND_DO_UCALL: + case ZEND_DO_FCALL_BY_NAME: call--; if (call_stack[call].func && call_stack[call].opline) { zend_op *fcall = call_stack[call].opline; @@ -85,6 +88,7 @@ void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx) Z_CACHE_SLOT(op_array->literals[fcall->op2.constant + 1]) = Z_CACHE_SLOT(op_array->literals[fcall->op2.constant]); literal_dtor(&ZEND_OP2_LITERAL(fcall)); fcall->op2.constant = fcall->op2.constant + 1; + opline->opcode = zend_get_call_op(ZEND_INIT_FCALL, call_stack[call].func); } else if (fcall->opcode == ZEND_INIT_NS_FCALL_BY_NAME) { fcall->opcode = ZEND_INIT_FCALL; fcall->op1.num = zend_vm_calc_used_stack(fcall->extended_value, call_stack[call].func); @@ -92,6 +96,7 @@ void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx) literal_dtor(&op_array->literals[fcall->op2.constant]); literal_dtor(&op_array->literals[fcall->op2.constant + 2]); fcall->op2.constant = fcall->op2.constant + 1; + opline->opcode = zend_get_call_op(ZEND_INIT_FCALL, call_stack[call].func); } else { ZEND_ASSERT(0); } diff --git a/ext/opcache/Optimizer/pass1_5.c b/ext/opcache/Optimizer/pass1_5.c index 341e80501b..990b845d43 100644 --- a/ext/opcache/Optimizer/pass1_5.c +++ b/ext/opcache/Optimizer/pass1_5.c @@ -341,7 +341,7 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx) } break; - case ZEND_DO_FCALL: { + case ZEND_DO_ICALL: { zend_op *send1_opline = opline - 1; zend_op *send2_opline = NULL; zend_op *init_opline = NULL; diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index cdcbfeda56..3aa90fb738 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -1836,6 +1836,11 @@ static void accel_activate(void) return; } + if (!ZCG(function_table).nTableSize) { + zend_hash_init(&ZCG(function_table), zend_hash_num_elements(CG(function_table)), NULL, ZEND_FUNCTION_DTOR, 1); + zend_accel_copy_internal_functions(); + } + SHM_UNPROTECT(); /* PHP-5.4 and above return "double", but we use 1 sec precision */ ZCG(auto_globals_mask) = 0; @@ -2257,8 +2262,6 @@ static void accel_globals_ctor(zend_accel_globals *accel_globals) ZEND_TSRMLS_CACHE_UPDATE(); #endif memset(accel_globals, 0, sizeof(zend_accel_globals)); - zend_hash_init(&accel_globals->function_table, zend_hash_num_elements(CG(function_table)), NULL, ZEND_FUNCTION_DTOR, 1); - zend_accel_copy_internal_functions(); } static void accel_globals_internal_func_dtor(zval *zv) @@ -2268,8 +2271,10 @@ static void accel_globals_internal_func_dtor(zval *zv) static void accel_globals_dtor(zend_accel_globals *accel_globals) { - accel_globals->function_table.pDestructor = accel_globals_internal_func_dtor; - zend_hash_destroy(&accel_globals->function_table); + if (accel_globals->function_table.nTableSize) { + accel_globals->function_table.pDestructor = accel_globals_internal_func_dtor; + zend_hash_destroy(&accel_globals->function_table); + } } static int accel_startup(zend_extension *extension) @@ -2422,11 +2427,6 @@ static int accel_startup(zend_extension *extension) zend_accel_blacklist_load(&accel_blacklist, ZCG(accel_directives.user_blacklist_filename)); } -#if 0 - /* FIXME: We probably don't need it here */ - zend_accel_copy_internal_functions(); -#endif - return SUCCESS; } diff --git a/sapi/phpdbg/phpdbg_prompt.c b/sapi/phpdbg/phpdbg_prompt.c index 6e492b7aaa..72cb2e018c 100644 --- a/sapi/phpdbg/phpdbg_prompt.c +++ b/sapi/phpdbg/phpdbg_prompt.c @@ -1454,7 +1454,10 @@ next: PHPDBG_G(last_line) = execute_data->opline->lineno; /* stupid hack to make zend_do_fcall_common_helper return ZEND_VM_ENTER() instead of recursively calling zend_execute() and eventually segfaulting */ - if (execute_data->opline->opcode == ZEND_DO_FCALL && execute_data->func->type == ZEND_USER_FUNCTION) { + if ((execute_data->opline->opcode == ZEND_DO_FCALL || + execute_data->opline->opcode == ZEND_DO_UCALL || + execute_data->opline->opcode == ZEND_DO_FCALL_BY_NAME) && + execute_data->func->type == ZEND_USER_FUNCTION) { zend_execute_ex = execute_ex; } PHPDBG_G(vmret) = execute_data->opline->handler(execute_data);