Move rare cases of DO_FCALL into separate helpers.

This commit is contained in:
Dmitry Stogov 2016-04-13 20:13:17 +03:00
parent 85f35a8fc1
commit e95efb6312
3 changed files with 124 additions and 225 deletions

View File

@ -769,6 +769,23 @@ static int zend_verify_internal_arg_type(zend_function *zf, uint32_t arg_num, zv
return 1;
}
static zend_never_inline int zend_verify_internal_arg_types(zend_function *fbc, zend_execute_data *call)
{
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) {
if (UNEXPECTED(!zend_verify_internal_arg_type(fbc, i + 1, p))) {
EG(current_execute_data) = call->prev_execute_data;
zend_vm_stack_free_args(call);
return 0;
}
p++;
}
return 1;
}
static zend_always_inline int zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, zval *default_value, void **cache_slot)
{
zend_arg_info *cur_arg_info;
@ -2930,6 +2947,44 @@ already_compiled:
}
/* }}} */
static zend_never_inline int zend_do_fcall_overloaded(zend_function *fbc, zend_execute_data *call, zval *ret) /* {{{ */
{
zend_object *object;
/* Not sure what should be done here if it's a static method */
if (UNEXPECTED(Z_TYPE(call->This) != IS_OBJECT)) {
zend_vm_stack_free_args(call);
if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
zend_string_release(fbc->common.function_name);
}
efree(fbc);
zend_vm_stack_free_call_frame(call);
zend_throw_error(NULL, "Cannot call overloaded function for non-object");
return 0;
}
object = Z_OBJ(call->This);
EG(scope) = fbc->common.scope;
ZVAL_NULL(ret);
Z_VAR_FLAGS_P(ret) = 0;
EG(current_execute_data) = call;
object->handlers->call_method(fbc->common.function_name, object, call, ret);
EG(current_execute_data) = call->prev_execute_data;
zend_vm_stack_free_args(call);
if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
zend_string_release(fbc->common.function_name);
}
efree(fbc);
return 1;
}
/* }}} */
#ifdef HAVE_GCC_GLOBAL_REGS
# if defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(i386)
# define ZEND_VM_FP_GLOBAL_REG "%esi"

View File

@ -3617,21 +3617,11 @@ ZEND_VM_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL))
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) {
if (UNEXPECTED(!zend_verify_internal_arg_type(fbc, i + 1, p))) {
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();
}
p++;
}
if (UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS)
&& UNEXPECTED(!zend_verify_internal_arg_types(fbc, call))) {
zend_vm_stack_free_call_frame(call);
zend_throw_exception_internal(NULL);
HANDLE_EXCEPTION();
}
ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval;
@ -3739,25 +3729,15 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL))
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) {
if (UNEXPECTED(!zend_verify_internal_arg_type(fbc, i + 1, p))) {
EG(current_execute_data) = call->prev_execute_data;
zend_vm_stack_free_args(call);
if (RETURN_VALUE_USED(opline)) {
ZVAL_UNDEF(EX_VAR(opline->result.var));
}
if (UNEXPECTED(should_change_scope)) {
ZEND_VM_C_GOTO(fcall_end_change_scope);
} else {
ZEND_VM_C_GOTO(fcall_end);
}
}
p++;
if (UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS)
&& UNEXPECTED(!zend_verify_internal_arg_types(fbc, call))) {
if (RETURN_VALUE_USED(opline)) {
ZVAL_UNDEF(EX_VAR(opline->result.var));
}
if (UNEXPECTED(should_change_scope)) {
ZEND_VM_C_GOTO(fcall_end_change_scope);
} else {
ZEND_VM_C_GOTO(fcall_end);
}
}
@ -3793,41 +3773,17 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL))
}
} else { /* ZEND_OVERLOADED_FUNCTION */
zval retval;
/* Not sure what should be done here if it's a static method */
if (UNEXPECTED(Z_TYPE(call->This) != IS_OBJECT)) {
zend_vm_stack_free_args(call);
if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
zend_string_release(fbc->common.function_name);
}
efree(fbc);
zend_vm_stack_free_call_frame(call);
zend_throw_error(NULL, "Cannot call overloaded function for non-object");
ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval;
call->prev_execute_data = execute_data;
if (UNEXPECTED(!zend_do_fcall_overloaded(fbc, call, ret))) {
HANDLE_EXCEPTION();
}
object = Z_OBJ(call->This);
EG(scope) = fbc->common.scope;
ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval;
ZVAL_NULL(ret);
call->prev_execute_data = execute_data;
EG(current_execute_data) = call;
object->handlers->call_method(fbc->common.function_name, object, call, ret);
EG(current_execute_data) = call->prev_execute_data;
zend_vm_stack_free_args(call);
if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
zend_string_release(fbc->common.function_name);
}
efree(fbc);
if (!RETURN_VALUE_USED(opline)) {
zval_ptr_dtor(ret);
} else {
Z_VAR_FLAGS_P(ret) = 0;
}
}
@ -7922,25 +7878,13 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY)
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);
EG(current_execute_data) = call;
for (i = 0; i < num_args; ++i) {
if (UNEXPECTED(!zend_verify_internal_arg_type(fbc, i + 1, p))) {
EG(current_execute_data) = call->prev_execute_data;
zend_vm_stack_free_args(call);
zend_vm_stack_free_call_frame(call);
if (ret) {
ZVAL_UNDEF(ret);
}
ZEND_VM_C_GOTO(call_trampoline_end);
}
p++;
if (UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS)
&& UNEXPECTED(!zend_verify_internal_arg_types(fbc, call))) {
zend_vm_stack_free_call_frame(call);
if (ret) {
ZVAL_UNDEF(ret);
}
ZEND_VM_C_GOTO(call_trampoline_end);
}
if (ret == NULL) {

View File

@ -793,21 +793,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_U
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) {
if (UNEXPECTED(!zend_verify_internal_arg_type(fbc, i + 1, p))) {
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();
}
p++;
}
if (UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS)
&& UNEXPECTED(!zend_verify_internal_arg_types(fbc, call))) {
zend_vm_stack_free_call_frame(call);
zend_throw_exception_internal(NULL);
HANDLE_EXCEPTION();
}
ret = 0 ? EX_VAR(opline->result.var) : &retval;
@ -897,21 +887,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_U
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) {
if (UNEXPECTED(!zend_verify_internal_arg_type(fbc, i + 1, p))) {
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();
}
p++;
}
if (UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS)
&& UNEXPECTED(!zend_verify_internal_arg_types(fbc, call))) {
zend_vm_stack_free_call_frame(call);
zend_throw_exception_internal(NULL);
HANDLE_EXCEPTION();
}
ret = 1 ? EX_VAR(opline->result.var) : &retval;
@ -1019,25 +999,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_HA
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) {
if (UNEXPECTED(!zend_verify_internal_arg_type(fbc, i + 1, p))) {
EG(current_execute_data) = call->prev_execute_data;
zend_vm_stack_free_args(call);
if (0) {
ZVAL_UNDEF(EX_VAR(opline->result.var));
}
if (UNEXPECTED(should_change_scope)) {
goto fcall_end_change_scope;
} else {
goto fcall_end;
}
}
p++;
if (UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS)
&& UNEXPECTED(!zend_verify_internal_arg_types(fbc, call))) {
if (0) {
ZVAL_UNDEF(EX_VAR(opline->result.var));
}
if (UNEXPECTED(should_change_scope)) {
goto fcall_end_change_scope;
} else {
goto fcall_end;
}
}
@ -1073,41 +1043,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_HA
}
} else { /* ZEND_OVERLOADED_FUNCTION */
zval retval;
/* Not sure what should be done here if it's a static method */
if (UNEXPECTED(Z_TYPE(call->This) != IS_OBJECT)) {
zend_vm_stack_free_args(call);
if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
zend_string_release(fbc->common.function_name);
}
efree(fbc);
zend_vm_stack_free_call_frame(call);
zend_throw_error(NULL, "Cannot call overloaded function for non-object");
ret = 0 ? EX_VAR(opline->result.var) : &retval;
call->prev_execute_data = execute_data;
if (UNEXPECTED(!zend_do_fcall_overloaded(fbc, call, ret))) {
HANDLE_EXCEPTION();
}
object = Z_OBJ(call->This);
EG(scope) = fbc->common.scope;
ret = 0 ? EX_VAR(opline->result.var) : &retval;
ZVAL_NULL(ret);
call->prev_execute_data = execute_data;
EG(current_execute_data) = call;
object->handlers->call_method(fbc->common.function_name, object, call, ret);
EG(current_execute_data) = call->prev_execute_data;
zend_vm_stack_free_args(call);
if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
zend_string_release(fbc->common.function_name);
}
efree(fbc);
if (!0) {
zval_ptr_dtor(ret);
} else {
Z_VAR_FLAGS_P(ret) = 0;
}
}
@ -1214,25 +1160,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETVAL_USED_HAND
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) {
if (UNEXPECTED(!zend_verify_internal_arg_type(fbc, i + 1, p))) {
EG(current_execute_data) = call->prev_execute_data;
zend_vm_stack_free_args(call);
if (1) {
ZVAL_UNDEF(EX_VAR(opline->result.var));
}
if (UNEXPECTED(should_change_scope)) {
goto fcall_end_change_scope;
} else {
goto fcall_end;
}
}
p++;
if (UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS)
&& UNEXPECTED(!zend_verify_internal_arg_types(fbc, call))) {
if (1) {
ZVAL_UNDEF(EX_VAR(opline->result.var));
}
if (UNEXPECTED(should_change_scope)) {
goto fcall_end_change_scope;
} else {
goto fcall_end;
}
}
@ -1268,41 +1204,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETVAL_USED_HAND
}
} else { /* ZEND_OVERLOADED_FUNCTION */
zval retval;
/* Not sure what should be done here if it's a static method */
if (UNEXPECTED(Z_TYPE(call->This) != IS_OBJECT)) {
zend_vm_stack_free_args(call);
if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
zend_string_release(fbc->common.function_name);
}
efree(fbc);
zend_vm_stack_free_call_frame(call);
zend_throw_error(NULL, "Cannot call overloaded function for non-object");
ret = 1 ? EX_VAR(opline->result.var) : &retval;
call->prev_execute_data = execute_data;
if (UNEXPECTED(!zend_do_fcall_overloaded(fbc, call, ret))) {
HANDLE_EXCEPTION();
}
object = Z_OBJ(call->This);
EG(scope) = fbc->common.scope;
ret = 1 ? EX_VAR(opline->result.var) : &retval;
ZVAL_NULL(ret);
call->prev_execute_data = execute_data;
EG(current_execute_data) = call;
object->handlers->call_method(fbc->common.function_name, object, call, ret);
EG(current_execute_data) = call->prev_execute_data;
zend_vm_stack_free_args(call);
if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
zend_string_release(fbc->common.function_name);
}
efree(fbc);
if (!1) {
zval_ptr_dtor(ret);
} else {
Z_VAR_FLAGS_P(ret) = 0;
}
}
@ -2148,25 +2060,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_HANDLER(Z
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);
EG(current_execute_data) = call;
for (i = 0; i < num_args; ++i) {
if (UNEXPECTED(!zend_verify_internal_arg_type(fbc, i + 1, p))) {
EG(current_execute_data) = call->prev_execute_data;
zend_vm_stack_free_args(call);
zend_vm_stack_free_call_frame(call);
if (ret) {
ZVAL_UNDEF(ret);
}
goto call_trampoline_end;
}
p++;
if (UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS)
&& UNEXPECTED(!zend_verify_internal_arg_types(fbc, call))) {
zend_vm_stack_free_call_frame(call);
if (ret) {
ZVAL_UNDEF(ret);
}
goto call_trampoline_end;
}
if (ret == NULL) {