diff --git a/Zend/zend_API.h b/Zend/zend_API.h index 944bef850dd2..ae391d98e5bd 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -563,6 +563,37 @@ ZEND_API int zend_fcall_info_call(zend_fcall_info *fci, zend_fcall_info_cache *f ZEND_API int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache); +/* Call the provided zend_function with the given params. + * If retval_ptr is NULL, the return value is discarded. + * If object is NULL, this must be a free function or static call. + * called_scope must be provided for instance and static method calls. */ +ZEND_API void zend_call_known_function( + zend_function *fn, zend_object *object, zend_class_entry *called_scope, zval *retval_ptr, + uint32_t param_count, zval *params); + +/* Call the provided zend_function instance method on an object. */ +static zend_always_inline void zend_call_known_instance_method( + zend_function *fn, zend_object *object, zval *retval_ptr, + uint32_t param_count, zval *params) +{ + zend_call_known_function(fn, object, object->ce, retval_ptr, param_count, params); +} + +static zend_always_inline void zend_call_known_instance_method_with_0_params( + zend_function *fn, zend_object *object, zval *retval_ptr) +{ + zend_call_known_instance_method(fn, object, retval_ptr, 0, NULL); +} + +static zend_always_inline void zend_call_known_instance_method_with_1_params( + zend_function *fn, zend_object *object, zval *retval_ptr, zval *param) +{ + zend_call_known_instance_method(fn, object, retval_ptr, 1, param); +} + +ZEND_API void zend_call_known_instance_method_with_2_params( + zend_function *fn, zend_object *object, zval *retval_ptr, zval *param1, zval *param2); + ZEND_API int zend_set_hash_symbol(zval *symbol, const char *name, int name_length, zend_bool is_ref, int num_symbol_tables, ...); ZEND_API int zend_delete_global_variable(zend_string *name); diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index 57eb01082106..594186682b89 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -922,7 +922,7 @@ ZEND_API ZEND_COLD void zend_exception_error(zend_object *ex, int severity) /* { zend_string *str, *file = NULL; zend_long line = 0; - zend_call_method_with_0_params(Z_OBJ(exception), ce_exception, &ex->ce->__tostring, "__tostring", &tmp); + zend_call_known_instance_method_with_0_params(ex->ce->__tostring, Z_OBJ(exception), &tmp); if (!EG(exception)) { if (Z_TYPE(tmp) != IS_STRING) { zend_error(E_WARNING, "%s::__toString() must return a string", ZSTR_VAL(ce_exception->name)); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 1b48bed125f8..5480dc48b2ac 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -861,6 +861,51 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / } /* }}} */ +ZEND_API void zend_call_known_function( + zend_function *fn, zend_object *object, zend_class_entry *called_scope, zval *retval_ptr, + uint32_t param_count, zval *params) +{ + zval retval; + zend_fcall_info fci; + zend_fcall_info_cache fcic; + + ZEND_ASSERT(fn && "zend_function must be passed!"); + + fci.size = sizeof(fci); + fci.object = object; + fci.retval = retval_ptr ? retval_ptr : &retval; + fci.param_count = param_count; + fci.params = params; + fci.no_separation = 1; + ZVAL_UNDEF(&fci.function_name); /* Unused */ + + fcic.function_handler = fn; + fcic.object = object; + fcic.called_scope = called_scope; + + int result = zend_call_function(&fci, &fcic); + if (result == FAILURE) { + if (!EG(exception)) { + zend_error_noreturn(E_CORE_ERROR, "Couldn't execute method %s%s%s", + fn->common.scope ? ZSTR_VAL(fn->common.scope->name) : "", + fn->common.scope ? "::" : "", ZSTR_VAL(fn->common.function_name)); + } + } + + if (!retval_ptr) { + zval_ptr_dtor(&retval); + } +} + +ZEND_API void zend_call_known_instance_method_with_2_params( + zend_function *fn, zend_object *object, zval *retval_ptr, zval *param1, zval *param2) +{ + zval params[2]; + ZVAL_COPY_VALUE(¶ms[0], param1); + ZVAL_COPY_VALUE(¶ms[1], param2); + zend_call_known_instance_method(fn, object, retval_ptr, 2, params); +} + ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string *key, uint32_t flags) /* {{{ */ { zend_class_entry *ce = NULL; diff --git a/Zend/zend_interfaces.c b/Zend/zend_interfaces.c index 6ad81c080539..6925d990e47c 100644 --- a/Zend/zend_interfaces.c +++ b/Zend/zend_interfaces.c @@ -34,10 +34,8 @@ ZEND_API zend_class_entry *zend_ce_stringable; Only returns the returned zval if retval_ptr != NULL */ ZEND_API zval* zend_call_method(zend_object *object, zend_class_entry *obj_ce, zend_function **fn_proxy, const char *function_name, size_t function_name_len, zval *retval_ptr, int param_count, zval* arg1, zval* arg2) { - int result; - zend_fcall_info fci; - zend_fcall_info_cache fcic; - zval retval; + zend_function *fn; + zend_class_entry *called_scope; zval params[2]; if (param_count > 0) { @@ -47,68 +45,43 @@ ZEND_API zval* zend_call_method(zend_object *object, zend_class_entry *obj_ce, z ZVAL_COPY_VALUE(¶ms[1], arg2); } - fci.size = sizeof(fci); - fci.object = object; - fci.retval = retval_ptr ? retval_ptr : &retval; - fci.param_count = param_count; - fci.params = params; - fci.no_separation = 1; - ZVAL_UNDEF(&fci.function_name); /* Unused */ - if (!obj_ce) { obj_ce = object ? object->ce : NULL; } if (!fn_proxy || !*fn_proxy) { if (EXPECTED(obj_ce)) { - fcic.function_handler = zend_hash_str_find_ptr( + fn = zend_hash_str_find_ptr( &obj_ce->function_table, function_name, function_name_len); - if (UNEXPECTED(fcic.function_handler == NULL)) { + if (UNEXPECTED(fn == NULL)) { /* error at c-level */ zend_error_noreturn(E_CORE_ERROR, "Couldn't find implementation for method %s::%s", ZSTR_VAL(obj_ce->name), function_name); } } else { - fcic.function_handler = zend_fetch_function_str(function_name, function_name_len); - if (UNEXPECTED(fcic.function_handler == NULL)) { + fn = zend_fetch_function_str(function_name, function_name_len); + if (UNEXPECTED(fn == NULL)) { /* error at c-level */ zend_error_noreturn(E_CORE_ERROR, "Couldn't find implementation for function %s", function_name); } } if (fn_proxy) { - *fn_proxy = fcic.function_handler; + *fn_proxy = fn; } } else { - fcic.function_handler = *fn_proxy; + fn = *fn_proxy; } if (object) { - fcic.called_scope = object->ce; + called_scope = object->ce; } else { - zend_class_entry *called_scope = zend_get_called_scope(EG(current_execute_data)); - + called_scope = zend_get_called_scope(EG(current_execute_data)); if (obj_ce && (!called_scope || !instanceof_function(called_scope, obj_ce))) { - fcic.called_scope = obj_ce; - } else { - fcic.called_scope = called_scope; + called_scope = obj_ce; } } - fcic.object = object; - result = zend_call_function(&fci, &fcic); - if (result == FAILURE) { - /* error at c-level */ - if (!obj_ce) { - obj_ce = object ? object->ce : NULL; - } - if (!EG(exception)) { - zend_error_noreturn(E_CORE_ERROR, "Couldn't execute method %s%s%s", obj_ce ? ZSTR_VAL(obj_ce->name) : "", obj_ce ? "::" : "", function_name); - } - } - if (!retval_ptr) { - zval_ptr_dtor(&retval); - return NULL; - } + zend_call_known_function(fn, object, called_scope, retval_ptr, param_count, params); return retval_ptr; } /* }}} */ @@ -390,8 +363,7 @@ ZEND_API int zend_user_serialize(zval *object, unsigned char **buffer, size_t *b zval retval; int result; - zend_call_method_with_0_params(Z_OBJ_P(object), ce, &ce->serialize_func, "serialize", &retval); - + zend_call_known_instance_method_with_0_params(ce->serialize_func, Z_OBJ_P(object), &retval); if (Z_TYPE(retval) == IS_UNDEF || EG(exception)) { result = FAILURE; @@ -430,9 +402,8 @@ ZEND_API int zend_user_unserialize(zval *object, zend_class_entry *ce, const uns } ZVAL_STRINGL(&zdata, (char*)buf, buf_len); - - zend_call_method_with_1_params(Z_OBJ_P(object), ce, &ce->unserialize_func, "unserialize", NULL, &zdata); - + zend_call_known_instance_method_with_1_params( + ce->unserialize_func, Z_OBJ_P(object), NULL, &zdata); zval_ptr_dtor(&zdata); if (EG(exception)) { diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 81a1b7b776b2..5a0b8b1f7815 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -149,7 +149,7 @@ ZEND_API HashTable *zend_std_get_debug_info(zend_object *object, int *is_temp) / return object->handlers->get_properties(object); } - zend_call_method_with_0_params(object, ce, &ce->__debugInfo, ZEND_DEBUGINFO_FUNC_NAME, &retval); + zend_call_known_instance_method_with_0_params(ce->__debugInfo, object, &retval); if (Z_TYPE(retval) == IS_ARRAY) { if (!Z_REFCOUNTED(retval)) { *is_temp = 1; @@ -1801,7 +1801,7 @@ ZEND_API int zend_std_cast_object_tostring(zend_object *readobj, zval *writeobj, if (ce->__tostring) { zval retval; GC_ADDREF(readobj); - zend_call_method_with_0_params(readobj, ce, &ce->__tostring, "__tostring", &retval); + zend_call_known_instance_method_with_0_params(ce->__tostring, readobj, &retval); zend_object_release(readobj); if (EXPECTED(Z_TYPE(retval) == IS_STRING)) { ZVAL_COPY_VALUE(writeobj, &retval); diff --git a/ext/intl/calendar/calendar_methods.cpp b/ext/intl/calendar/calendar_methods.cpp index 45fe97d50912..186c2597f427 100644 --- a/ext/intl/calendar/calendar_methods.cpp +++ b/ext/intl/calendar/calendar_methods.cpp @@ -1016,7 +1016,8 @@ U_CFUNC PHP_FUNCTION(intlcal_from_date_time) if (!(Z_TYPE_P(zv_arg) == IS_OBJECT && instanceof_function( Z_OBJCE_P(zv_arg), php_date_get_date_ce()))) { object_init_ex(&zv_tmp, php_date_get_date_ce()); - zend_call_method_with_1_params(Z_OBJ(zv_tmp), NULL, &Z_OBJCE(zv_tmp)->constructor, "__construct", NULL, zv_arg); + zend_call_known_instance_method_with_1_params( + Z_OBJCE(zv_tmp)->constructor, Z_OBJ(zv_tmp), NULL, zv_arg); zv_datetime = &zv_tmp; if (EG(exception)) { zend_object_store_ctor_failed(Z_OBJ(zv_tmp)); @@ -1130,7 +1131,8 @@ U_CFUNC PHP_FUNCTION(intlcal_to_date_time) /* Finally, instantiate object and call constructor */ object_init_ex(return_value, php_date_get_date_ce()); - zend_call_method_with_2_params(Z_OBJ_P(return_value), NULL, &Z_OBJCE_P(return_value)->constructor, "__construct", NULL, &ts_zval, timezone_zval); + zend_call_known_instance_method_with_2_params( + Z_OBJCE_P(return_value)->constructor, Z_OBJ_P(return_value), NULL, &ts_zval, timezone_zval); if (EG(exception)) { intl_errors_set(CALENDAR_ERROR_P(co), U_ILLEGAL_ARGUMENT_ERROR, "intlcal_to_date_time: DateTime constructor has thrown exception", diff --git a/ext/intl/timezone/timezone_class.cpp b/ext/intl/timezone/timezone_class.cpp index b3d447f5d51a..63d5b057467f 100644 --- a/ext/intl/timezone/timezone_class.cpp +++ b/ext/intl/timezone/timezone_class.cpp @@ -96,7 +96,8 @@ U_CFUNC zval *timezone_convert_to_datetimezone(const TimeZone *timeZone, goto error; } ZVAL_STR(&arg, u8str); - zend_call_method_with_1_params(Z_OBJ_P(ret), NULL, &Z_OBJCE_P(ret)->constructor, "__construct", NULL, &arg); + zend_call_known_instance_method_with_1_params( + Z_OBJCE_P(ret)->constructor, Z_OBJ_P(ret), NULL, &arg); if (EG(exception)) { spprintf(&message, 0, "%s: DateTimeZone constructor threw exception", func); diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 351d342c53a9..d273e1d519c2 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -1242,8 +1242,8 @@ PHP_METHOD(Phar, __construct) ZVAL_STRINGL(&arg1, fname, fname_len); ZVAL_LONG(&arg2, flags); - zend_call_method_with_2_params(Z_OBJ_P(zobj), Z_OBJCE_P(zobj), - &spl_ce_RecursiveDirectoryIterator->constructor, "__construct", NULL, &arg1, &arg2); + zend_call_known_instance_method_with_2_params(spl_ce_RecursiveDirectoryIterator->constructor, + Z_OBJ_P(zobj), NULL, &arg1, &arg2); zval_ptr_dtor(&arg1); @@ -1764,8 +1764,8 @@ PHP_METHOD(Phar, buildFromDirectory) ZVAL_STRINGL(&arg, dir, dir_len); ZVAL_LONG(&arg2, SPL_FILE_DIR_SKIPDOTS|SPL_FILE_DIR_UNIXPATHS); - zend_call_method_with_2_params(Z_OBJ(iter), spl_ce_RecursiveDirectoryIterator, - &spl_ce_RecursiveDirectoryIterator->constructor, "__construct", NULL, &arg, &arg2); + zend_call_known_instance_method_with_2_params(spl_ce_RecursiveDirectoryIterator->constructor, + Z_OBJ(iter), NULL, &arg, &arg2); zval_ptr_dtor(&arg); if (EG(exception)) { @@ -1780,8 +1780,8 @@ PHP_METHOD(Phar, buildFromDirectory) RETURN_THROWS(); } - zend_call_method_with_1_params(Z_OBJ(iteriter), spl_ce_RecursiveIteratorIterator, - &spl_ce_RecursiveIteratorIterator->constructor, "__construct", NULL, &iter); + zend_call_known_instance_method_with_1_params(spl_ce_RecursiveIteratorIterator->constructor, + Z_OBJ(iteriter), NULL, &iter); if (EG(exception)) { zval_ptr_dtor(&iter); @@ -1803,8 +1803,8 @@ PHP_METHOD(Phar, buildFromDirectory) ZVAL_STRINGL(&arg2, regex, regex_len); - zend_call_method_with_2_params(Z_OBJ(regexiter), spl_ce_RegexIterator, - &spl_ce_RegexIterator->constructor, "__construct", NULL, &iteriter, &arg2); + zend_call_known_instance_method_with_2_params(spl_ce_RegexIterator->constructor, + Z_OBJ(regexiter), NULL, &iteriter, &arg2); zval_ptr_dtor(&arg2); } @@ -2256,7 +2256,7 @@ static zend_object *phar_rename_archive(phar_archive_data **sphar, char *ext) /* ZVAL_STRINGL(&arg1, phar->fname, phar->fname_len); - zend_call_method_with_1_params(Z_OBJ(ret), ce, &ce->constructor, "__construct", NULL, &arg1); + zend_call_known_instance_method_with_1_params(ce->constructor, Z_OBJ(ret), NULL, &arg1); zval_ptr_dtor(&arg1); return Z_OBJ(ret); } @@ -4539,8 +4539,8 @@ PHP_METHOD(PharFileInfo, __construct) ZVAL_STRINGL(&arg1, fname, fname_len); - zend_call_method_with_1_params(Z_OBJ_P(zobj), Z_OBJCE_P(zobj), - &spl_ce_SplFileInfo->constructor, "__construct", NULL, &arg1); + zend_call_known_instance_method_with_1_params(spl_ce_SplFileInfo->constructor, + Z_OBJ_P(zobj), NULL, &arg1); zval_ptr_dtor(&arg1); } diff --git a/sapi/cli/php_cli.c b/sapi/cli/php_cli.c index 206d393b7e8c..a9069c6191af 100644 --- a/sapi/cli/php_cli.c +++ b/sapi/cli/php_cli.c @@ -1070,7 +1070,8 @@ static int do_cli(int argc, char **argv) /* {{{ */ memset(&execute_data, 0, sizeof(zend_execute_data)); EG(current_execute_data) = &execute_data; - zend_call_method_with_1_params(Z_OBJ(ref), pce, &pce->constructor, "__construct", NULL, &arg); + zend_call_known_instance_method_with_1_params( + pce->constructor, Z_OBJ(ref), NULL, &arg); if (EG(exception)) { zval tmp, *msg, rv; diff --git a/sapi/phpdbg/phpdbg_prompt.c b/sapi/phpdbg/phpdbg_prompt.c index 14e09d72432f..2f0e8e2440b6 100644 --- a/sapi/phpdbg/phpdbg_prompt.c +++ b/sapi/phpdbg/phpdbg_prompt.c @@ -726,7 +726,7 @@ static inline void phpdbg_handle_exception(void) /* {{{ */ EG(exception) = NULL; ZVAL_OBJ(&zv, ex); - zend_call_method_with_0_params(ex, ex->ce, &ex->ce->__tostring, "__tostring", &tmp); + zend_call_known_instance_method_with_0_params(ex->ce->__tostring, ex, &tmp); file = zval_get_string(zend_read_property(zend_get_exception_base(&zv), &zv, ZEND_STRL("file"), 1, &rv)); line = zval_get_long(zend_read_property(zend_get_exception_base(&zv), &zv, ZEND_STRL("line"), 1, &rv));