diff options
author | Robert Fancsik <robert.fancsik@h-lab.eu> | 2021-11-04 17:26:28 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-04 17:26:28 +0100 |
commit | bc091e174206b26e3ff71a9833e37527579b035f (patch) | |
tree | dc5601e49b5bd4fdb6aee85ac8bc5771a0833c4f /jerry-core/ecma | |
parent | 7ea0000ee0b5b5a6dc58b70b3412a8b653bca1e8 (diff) |
Optimize ecma_op_function_call (#4817)
Remove redundant isCallable checks
JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik robert.fancsik@h-lab.eu
Diffstat (limited to 'jerry-core/ecma')
8 files changed, 256 insertions, 232 deletions
diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-async-from-sync-iterator-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-async-from-sync-iterator-prototype.c index eb26c2ee..1c25e172 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-async-from-sync-iterator-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-async-from-sync-iterator-prototype.c @@ -241,19 +241,8 @@ ecma_builtin_async_from_sync_iterator_prototype_do (ecma_async_from_sync_iterato } /* 8. */ - ecma_value_t call_result; - - if (!ecma_op_is_callable (method)) - { - ecma_free_value (method); - call_result = ecma_raise_type_error (ECMA_ERR_MSG (ecma_error_expected_a_function)); - } - else - { - ecma_object_t *method_func_obj = ecma_get_object_from_value (method); - call_result = ecma_op_function_call (method_func_obj, sync_iterator, &call_arg, arg_size); - ecma_deref_object (method_func_obj); - } + ecma_value_t call_result = ecma_op_function_validated_call (method, sync_iterator, &call_arg, arg_size); + ecma_free_value (method); /* 9. */ if (ECMA_IS_VALUE_ERROR (ecma_op_if_abrupt_reject_promise (&call_result, capability_obj_p))) diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.c index 377bc0fe..c1c09d65 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.c @@ -584,18 +584,10 @@ ecma_builtin_string_prototype_object_replace_helper (ecma_value_t this_value, /* if (!ecma_is_value_undefined (replace_symbol) && !ecma_is_value_null (replace_symbol)) { - if (!ecma_op_is_callable (replace_symbol)) - { - ecma_free_value (replace_symbol); - return ecma_raise_type_error (ECMA_ERR_MSG ("@@replace is not callable")); - } - - ecma_object_t *replace_method = ecma_get_object_from_value (replace_symbol); - ecma_value_t arguments[] = { this_value, replace_value }; - ecma_value_t replace_result = ecma_op_function_call (replace_method, search_value, arguments, 2); + ecma_value_t replace_result = ecma_op_function_validated_call (replace_symbol, search_value, arguments, 2); + ecma_free_value (replace_symbol); - ecma_deref_object (replace_method); return replace_result; } } @@ -800,16 +792,8 @@ ecma_builtin_string_prototype_object_search (ecma_value_t this_value, /**< this if (!ecma_is_value_undefined (search_symbol) && !ecma_is_value_null (search_symbol)) { - if (!ecma_op_is_callable (search_symbol)) - { - ecma_free_value (search_symbol); - return ecma_raise_type_error (ECMA_ERR_MSG ("@@search is not callable")); - } - - ecma_object_t *search_method = ecma_get_object_from_value (search_symbol); - ecma_value_t search_result = ecma_op_function_call (search_method, regexp_value, &this_value, 1); - - ecma_deref_object (search_method); + ecma_value_t search_result = ecma_op_function_validated_call (search_symbol, regexp_value, &this_value, 1); + ecma_free_value (search_symbol); return search_result; } } @@ -977,18 +961,10 @@ ecma_builtin_string_prototype_object_split (ecma_value_t this_value, /**< this a if (!ecma_is_value_undefined (split_symbol) && !ecma_is_value_null (split_symbol)) { - if (!ecma_op_is_callable (split_symbol)) - { - ecma_free_value (split_symbol); - return ecma_raise_type_error (ECMA_ERR_MSG ("@@split is not callable")); - } - - ecma_object_t *split_method_p = ecma_get_object_from_value (split_symbol); - ecma_value_t arguments[] = { this_value, limit_value }; - ecma_value_t split_result = ecma_op_function_call (split_method_p, separator_value, arguments, 2); + ecma_value_t split_result = ecma_op_function_validated_call (split_symbol, separator_value, arguments, 2); + ecma_free_value (split_symbol); - ecma_deref_object (split_method_p); return split_result; } } diff --git a/jerry-core/ecma/operations/ecma-async-generator-object.c b/jerry-core/ecma/operations/ecma-async-generator-object.c index bec4c9aa..446e9cc9 100644 --- a/jerry-core/ecma/operations/ecma-async-generator-object.c +++ b/jerry-core/ecma/operations/ecma-async-generator-object.c @@ -97,29 +97,21 @@ ecma_async_generator_enqueue (vm_executable_object_t *async_generator_object_p, static ecma_value_t ecma_async_yield_call (ecma_value_t function, /**< function (takes reference) */ vm_executable_object_t *async_generator_object_p, /**< async generator */ - ecma_value_t argument, /**< argument passed to the function */ - const char *error_msg_p) /**< error message when the function is not callable */ + ecma_value_t argument) /**< argument passed to the function */ { - if (!ecma_is_value_object (function) || !ecma_op_is_callable (function)) - { - ecma_free_value (function); - return ecma_raise_type_error (error_msg_p); - } - - ecma_object_t *return_obj_p = ecma_get_object_from_value (function); ecma_value_t iterator = async_generator_object_p->iterator; ecma_value_t result; if (argument == ECMA_VALUE_EMPTY) { - result = ecma_op_function_call (return_obj_p, iterator, NULL, 0); + result = ecma_op_function_validated_call (function, iterator, NULL, 0); } else { - result = ecma_op_function_call (return_obj_p, iterator, &argument, 1); + result = ecma_op_function_validated_call (function, iterator, &argument, 1); } - ecma_deref_object (return_obj_p); + ecma_free_value (function); if (ECMA_IS_VALUE_ERROR (result)) { @@ -155,8 +147,7 @@ ecma_async_yield_throw (vm_executable_object_t *async_generator_object_p, /**< a result = ecma_async_yield_call (result, async_generator_object_p, - ECMA_VALUE_EMPTY, - ECMA_ERR_MSG ("Iterator 'return' is not callable")); + ECMA_VALUE_EMPTY); if (ECMA_IS_VALUE_ERROR (result)) { @@ -169,8 +160,7 @@ ecma_async_yield_throw (vm_executable_object_t *async_generator_object_p, /**< a result = ecma_async_yield_call (result, async_generator_object_p, - value, - ECMA_ERR_MSG ("Iterator 'throw' is not callable")); + value); if (ECMA_IS_VALUE_ERROR (result)) { @@ -419,8 +409,7 @@ ecma_await_continue (vm_executable_object_t *executable_object_p, /**< executabl result = ecma_async_yield_call (result, executable_object_p, - value, - ECMA_ERR_MSG ("Iterator 'return' is not callable")); + value); ecma_free_value (value); if (ECMA_IS_VALUE_ERROR (result)) diff --git a/jerry-core/ecma/operations/ecma-function-object.c b/jerry-core/ecma/operations/ecma-function-object.c index 7c34dc36..0850a417 100644 --- a/jerry-core/ecma/operations/ecma-function-object.c +++ b/jerry-core/ecma/operations/ecma-function-object.c @@ -90,6 +90,23 @@ ecma_op_function_form_name (ecma_string_t *prop_name_p, /**< property name */ } /* ecma_op_function_form_name */ #endif /* JERRY_ESNEXT */ +#if JERRY_BUILTIN_PROXY +/** + * IsCallable operation for proxy object. + * + * @return true - if the given proxy object is callable; + * false - otherwise + */ +extern inline bool JERRY_ATTR_ALWAYS_INLINE +ecma_op_proxy_object_is_callable (ecma_object_t *obj_p) /**< ecma object */ +{ + JERRY_ASSERT (!ecma_is_lexical_environment (obj_p)); + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); + + return (obj_p->u2.prototype_cp & ECMA_PROXY_IS_CALLABLE) != 0; +} /* ecma_op_proxy_object_is_callable */ +#endif /* JERRY_BUILTIN_PROXY */ + /** * IsCallable operation. * @@ -108,7 +125,7 @@ ecma_op_object_is_callable (ecma_object_t *obj_p) /**< ecma object */ #if JERRY_BUILTIN_PROXY if (ECMA_OBJECT_TYPE_IS_PROXY (type)) { - return (obj_p->u2.prototype_cp & ECMA_PROXY_IS_CALLABLE) != 0; + return ecma_op_proxy_object_is_callable (obj_p); } #endif /* JERRY_BUILTIN_PROXY */ @@ -1022,6 +1039,76 @@ ecma_op_get_prototype_from_constructor (ecma_object_t *ctor_obj_p, /**< construc return proto_obj_p; } /* ecma_op_get_prototype_from_constructor */ +#if JERRY_ESNEXT +/** + * Perform a JavaScript class function object method call. + * + * The input function object should be a JavaScript class constructor + * + * @return the result of the function call. + */ +static ecma_value_t JERRY_ATTR_NOINLINE +ecma_op_function_call_constructor (vm_frame_ctx_shared_args_t *shared_args_p, /**< shared data */ + ecma_object_t *scope_p, /**< lexical environment to use */ + ecma_value_t this_binding) /**< value of 'ThisBinding' */ +{ + shared_args_p->header.status_flags |= VM_FRAME_CTX_SHARED_NON_ARROW_FUNC; + + ecma_value_t ret_value; + + if (JERRY_CONTEXT (current_new_target_p) == NULL) + { + ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Class constructor requires 'new'")); + goto exit; + } + + ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) shared_args_p->header.function_object_p; + if (ECMA_GET_THIRD_BIT_FROM_POINTER_TAG (ext_func_p->u.function.scope_cp)) + { + this_binding = ECMA_VALUE_UNINITIALIZED; + } + + ecma_op_create_environment_record (scope_p, this_binding, shared_args_p->header.function_object_p); + +#if JERRY_BUILTIN_REALMS + ecma_global_object_t *saved_global_object_p = JERRY_CONTEXT (global_object_p); + JERRY_CONTEXT (global_object_p) = ecma_op_function_get_realm (shared_args_p->header.bytecode_header_p); +#endif /* JERRY_BUILTIN_REALMS */ + + ret_value = vm_run (&shared_args_p->header, this_binding, scope_p); + +#if JERRY_BUILTIN_REALMS + JERRY_CONTEXT (global_object_p) = saved_global_object_p; +#endif /* JERRY_BUILTIN_REALMS */ + + /* ECMAScript v6, 9.2.2.13 */ + if (JERRY_UNLIKELY (this_binding == ECMA_VALUE_UNINITIALIZED)) + { + if (!ECMA_IS_VALUE_ERROR (ret_value) && !ecma_is_value_object (ret_value)) + { + if (!ecma_is_value_undefined (ret_value)) + { + ecma_free_value (ret_value); + ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Derived constructors may only return object or undefined")); + } + else + { + ret_value = ecma_op_get_this_binding (scope_p); + } + } + } + +exit: + if (JERRY_UNLIKELY (shared_args_p->header.status_flags & VM_FRAME_CTX_SHARED_FREE_LOCAL_ENV)) + { + ecma_deref_object (scope_p); + } + + return ret_value; +} /* ecma_op_function_call_constructor */ + +#endif /* JERRY_ESNEXT */ + /** * Perform a JavaScript function object method call. * @@ -1031,7 +1118,7 @@ ecma_op_get_prototype_from_constructor (ecma_object_t *ctor_obj_p, /**< construc */ static ecma_value_t ecma_op_function_call_simple (ecma_object_t *func_obj_p, /**< Function object */ - ecma_value_t this_arg_value, /**< 'this' argument's value */ + ecma_value_t this_binding, /**< 'this' argument's value */ const ecma_value_t *arguments_list_p, /**< arguments list */ uint32_t arguments_list_len) /**< length of arguments list */ { @@ -1050,8 +1137,6 @@ ecma_op_function_call_simple (ecma_object_t *func_obj_p, /**< Function object */ ext_func_p->u.function.scope_cp); /* 8. */ - ecma_value_t this_binding = this_arg_value; - const ecma_compiled_code_t *bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p); uint16_t status_flags = bytecode_data_p->status_flags; @@ -1061,29 +1146,50 @@ ecma_op_function_call_simple (ecma_object_t *func_obj_p, /**< Function object */ ecma_global_object_t *realm_p = ecma_op_function_get_realm (bytecode_data_p); #endif /* JERRY_BUILTIN_REALMS */ - /* 1. */ -#if JERRY_ESNEXT - if (JERRY_UNLIKELY (CBC_FUNCTION_IS_ARROW (status_flags))) + /* 5. */ + if (!(status_flags & CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED)) { - ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) func_obj_p; + shared_args.header.status_flags |= VM_FRAME_CTX_SHARED_FREE_LOCAL_ENV; + scope_p = ecma_create_decl_lex_env (scope_p); + } - if (ecma_is_value_undefined (arrow_func_p->new_target)) + /* 1. */ + switch (CBC_FUNCTION_GET_TYPE (status_flags)) + { +#if JERRY_ESNEXT + case CBC_FUNCTION_CONSTRUCTOR: { - JERRY_CONTEXT (current_new_target_p) = NULL; + return ecma_op_function_call_constructor (&shared_args, scope_p, this_binding); } - else + case CBC_FUNCTION_ARROW: { - JERRY_CONTEXT (current_new_target_p) = ecma_get_object_from_value (arrow_func_p->new_target); + ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) func_obj_p; + + if (ecma_is_value_undefined (arrow_func_p->new_target)) + { + JERRY_CONTEXT (current_new_target_p) = NULL; + } + else + { + JERRY_CONTEXT (current_new_target_p) = ecma_get_object_from_value (arrow_func_p->new_target); + } + + this_binding = arrow_func_p->this_binding; + break; } - this_binding = arrow_func_p->this_binding; - } - else - { - shared_args.header.status_flags |= VM_FRAME_CTX_SHARED_NON_ARROW_FUNC; -#endif /* JERRY_ESNEXT */ - if (!(status_flags & CBC_CODE_FLAGS_STRICT_MODE)) +#endif /* JERRY_ESNEXT */ + default: { +#if JERRY_ESNEXT + shared_args.header.status_flags |= VM_FRAME_CTX_SHARED_NON_ARROW_FUNC; +#endif /* JERRY_ESNEXT */ + + if (status_flags & CBC_CODE_FLAGS_STRICT_MODE) + { + break; + } + if (ecma_is_value_undefined (this_binding) || ecma_is_value_null (this_binding)) { @@ -1102,73 +1208,21 @@ ecma_op_function_call_simple (ecma_object_t *func_obj_p, /**< Function object */ JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (this_binding)); } + break; } -#if JERRY_ESNEXT - } -#endif /* JERRY_ESNEXT */ - - /* 5. */ - if (!(status_flags & CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED)) - { - shared_args.header.status_flags |= VM_FRAME_CTX_SHARED_FREE_LOCAL_ENV; - scope_p = ecma_create_decl_lex_env (scope_p); - } - - ecma_value_t ret_value; - -#if JERRY_ESNEXT - if (JERRY_UNLIKELY (CBC_FUNCTION_GET_TYPE (status_flags) == CBC_FUNCTION_CONSTRUCTOR)) - { - if (JERRY_CONTEXT (current_new_target_p) == NULL) - { - ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Class constructor requires 'new'")); - goto exit; - } - - ecma_value_t lexical_this = this_binding; - - if (ECMA_GET_THIRD_BIT_FROM_POINTER_TAG (ext_func_p->u.function.scope_cp)) - { - shared_args.header.status_flags |= VM_FRAME_CTX_SHARED_HERITAGE_PRESENT; - lexical_this = ECMA_VALUE_UNINITIALIZED; - } - - ecma_op_create_environment_record (scope_p, lexical_this, func_obj_p); } -#endif /* JERRY_ESNEXT */ #if JERRY_BUILTIN_REALMS ecma_global_object_t *saved_global_object_p = JERRY_CONTEXT (global_object_p); JERRY_CONTEXT (global_object_p) = realm_p; #endif /* JERRY_BUILTIN_REALMS */ - ret_value = vm_run (&shared_args.header, this_binding, scope_p); + ecma_value_t ret_value = vm_run (&shared_args.header, this_binding, scope_p); #if JERRY_BUILTIN_REALMS JERRY_CONTEXT (global_object_p) = saved_global_object_p; #endif /* JERRY_BUILTIN_REALMS */ -#if JERRY_ESNEXT - /* ECMAScript v6, 9.2.2.13 */ - if (JERRY_UNLIKELY (shared_args.header.status_flags & VM_FRAME_CTX_SHARED_HERITAGE_PRESENT)) - { - if (!ECMA_IS_VALUE_ERROR (ret_value) && !ecma_is_value_object (ret_value)) - { - if (!ecma_is_value_undefined (ret_value)) - { - ecma_free_value (ret_value); - ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Derived constructors may only return object or undefined")); - } - else - { - ret_value = ecma_op_get_this_binding (scope_p); - } - } - } - -exit: -#endif /* JERRY_ESNEXT */ - if (JERRY_UNLIKELY (shared_args.header.status_flags & VM_FRAME_CTX_SHARED_FREE_LOCAL_ENV)) { ecma_deref_object (scope_p); @@ -1350,11 +1404,30 @@ ecma_op_function_call_bound (ecma_object_t *func_obj_p, /**< Function object */ } /* ecma_op_function_call_bound */ /** - * [[Call]] implementation for Function objects, - * created through 13.2 (ECMA_OBJECT_TYPE_FUNCTION) - * or 15.3.4.5 (ECMA_OBJECT_TYPE_BOUND_FUNCTION), - * and for built-in Function objects - * from section 15 (ECMA_OBJECT_TYPE_FUNCTION). + * General [[Call]] implementation + * + * @return ecma value + * Returned value must be freed with ecma_free_value + */ +extern inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE +ecma_op_function_validated_call (ecma_value_t callee, /**< callee */ + ecma_value_t this_arg_value, /**< 'this' argument's value */ + const ecma_value_t *arguments_list_p, /**< arguments list */ + uint32_t arguments_list_len) /**< length of arguments list */ +{ + if (!ecma_is_value_object (callee)) + { + return ecma_raise_type_error (ECMA_ERR_MSG (ecma_error_expected_a_function)); + } + + return ecma_op_function_call (ecma_get_object_from_value (callee), + this_arg_value, + arguments_list_p, + arguments_list_len); +} /* ecma_op_function_validated_call */ + +/** + * General [[Call]] implementation * * @return ecma value * Returned value must be freed with ecma_free_value @@ -1367,21 +1440,12 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */ { JERRY_ASSERT (func_obj_p != NULL && !ecma_is_lexical_environment (func_obj_p)); - JERRY_ASSERT (ecma_op_object_is_callable (func_obj_p)); ECMA_CHECK_STACK_USAGE (); - const ecma_object_type_t type = ecma_get_object_type (func_obj_p); - -#if JERRY_BUILTIN_PROXY - if (ECMA_OBJECT_TYPE_IS_PROXY (type)) - { - return ecma_proxy_object_call (func_obj_p, this_arg_value, arguments_list_p, arguments_list_len); - } -#endif /* JERRY_BUILTIN_PROXY */ - #if JERRY_ESNEXT ecma_object_t *old_new_target_p = JERRY_CONTEXT (current_new_target_p); + if (JERRY_UNLIKELY (!(JERRY_CONTEXT (status_flags) & ECMA_STATUS_DIRECT_EVAL))) { JERRY_CONTEXT (current_new_target_p) = NULL; @@ -1390,27 +1454,47 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */ ecma_value_t result; - if (JERRY_LIKELY (type == ECMA_OBJECT_TYPE_FUNCTION)) - { - result = ecma_op_function_call_simple (func_obj_p, this_arg_value, arguments_list_p, arguments_list_len); - } - else if (type == ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION) - { - result = ecma_op_function_call_native_built_in (func_obj_p, this_arg_value, arguments_list_p, arguments_list_len); - } - else if (type == ECMA_OBJECT_TYPE_NATIVE_FUNCTION) + switch (ecma_get_object_type (func_obj_p)) { - result = ecma_op_function_call_native (func_obj_p, this_arg_value, arguments_list_p, arguments_list_len); - } + case ECMA_OBJECT_TYPE_FUNCTION: + { + result = ecma_op_function_call_simple (func_obj_p, this_arg_value, arguments_list_p, arguments_list_len); + break; + } + case ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION: + { + result = ecma_op_function_call_native_built_in (func_obj_p, this_arg_value, arguments_list_p, arguments_list_len); + break; + } +#if JERRY_BUILTIN_PROXY + case ECMA_OBJECT_TYPE_PROXY: + { + result = ecma_proxy_object_call (func_obj_p, this_arg_value, arguments_list_p, arguments_list_len); + break; + } +#endif /* JERRY_BUILTIN_PROXY */ #if JERRY_ESNEXT - else if (JERRY_UNLIKELY (type == ECMA_OBJECT_TYPE_CONSTRUCTOR_FUNCTION)) - { - result = ecma_raise_type_error (ECMA_ERR_MSG (ecma_error_class_constructor_new)); - } + case ECMA_OBJECT_TYPE_CONSTRUCTOR_FUNCTION: + { + result = ecma_raise_type_error (ECMA_ERR_MSG (ecma_error_class_constructor_new)); + break; + } #endif /* JERRY_ESNEXT */ - else - { - result = ecma_op_function_call_bound (func_obj_p, arguments_list_p, arguments_list_len); + case ECMA_OBJECT_TYPE_NATIVE_FUNCTION: + { + result = ecma_op_function_call_native (func_obj_p, this_arg_value, arguments_list_p, arguments_list_len); + break; + } + case ECMA_OBJECT_TYPE_BOUND_FUNCTION: + { + result = ecma_op_function_call_bound (func_obj_p, arguments_list_p, arguments_list_len); + break; + } + default: + { + result = ecma_raise_type_error (ECMA_ERR_MSG (ecma_error_expected_a_function)); + break; + } } #if JERRY_ESNEXT @@ -1704,39 +1788,43 @@ ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */ JERRY_ASSERT (func_obj_p != NULL && !ecma_is_lexical_environment (func_obj_p)); - const ecma_object_type_t type = ecma_get_object_type (func_obj_p); - - if (JERRY_LIKELY (type == ECMA_OBJECT_TYPE_FUNCTION)) - { - return ecma_op_function_construct_simple (func_obj_p, new_target_p, arguments_list_p, arguments_list_len); - } - - if (type == ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION) + switch (ecma_get_object_type (func_obj_p)) { - return ecma_op_function_construct_built_in (func_obj_p, new_target_p, arguments_list_p, arguments_list_len); - } - + case ECMA_OBJECT_TYPE_FUNCTION: + { + return ecma_op_function_construct_simple (func_obj_p, new_target_p, arguments_list_p, arguments_list_len); + } + case ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION: + { + return ecma_op_function_construct_built_in (func_obj_p, new_target_p, arguments_list_p, arguments_list_len); + } #if JERRY_BUILTIN_PROXY - if (ECMA_OBJECT_TYPE_IS_PROXY (type)) - { - return ecma_proxy_object_construct (func_obj_p, new_target_p, arguments_list_p, arguments_list_len); - } + case ECMA_OBJECT_TYPE_PROXY: + { + return ecma_proxy_object_construct (func_obj_p, new_target_p, arguments_list_p, arguments_list_len); + } #endif /* JERRY_BUILTIN_PROXY */ - - if (JERRY_UNLIKELY (type == ECMA_OBJECT_TYPE_BOUND_FUNCTION)) - { - return ecma_op_function_construct_bound (func_obj_p, new_target_p, arguments_list_p, arguments_list_len); - } - #if JERRY_ESNEXT - if (type == ECMA_OBJECT_TYPE_CONSTRUCTOR_FUNCTION) - { - return ecma_op_function_construct_constructor (func_obj_p, new_target_p, arguments_list_p, arguments_list_len); - } + case ECMA_OBJECT_TYPE_CONSTRUCTOR_FUNCTION: + { + return ecma_op_function_construct_constructor (func_obj_p, new_target_p, arguments_list_p, arguments_list_len); + } #endif /* JERRY_ESNEXT */ + case ECMA_OBJECT_TYPE_BOUND_FUNCTION: + { + return ecma_op_function_construct_bound (func_obj_p, new_target_p, arguments_list_p, arguments_list_len); + } + case ECMA_OBJECT_TYPE_NATIVE_FUNCTION: + { + return ecma_op_function_construct_native (func_obj_p, new_target_p, arguments_list_p, arguments_list_len); + } + default: + { + JERRY_UNREACHABLE (); + } + } - JERRY_ASSERT (type == ECMA_OBJECT_TYPE_NATIVE_FUNCTION); - return ecma_op_function_construct_native (func_obj_p, new_target_p, arguments_list_p, arguments_list_len); + return ECMA_VALUE_UNDEFINED; } /* ecma_op_function_construct */ /** diff --git a/jerry-core/ecma/operations/ecma-function-object.h b/jerry-core/ecma/operations/ecma-function-object.h index b2a710df..76c833a1 100644 --- a/jerry-core/ecma/operations/ecma-function-object.h +++ b/jerry-core/ecma/operations/ecma-function-object.h @@ -33,6 +33,9 @@ ecma_value_t ecma_op_function_form_name (ecma_string_t *prop_name_p, char *prefi #endif /* JERRY_ESNEXT */ bool ecma_op_is_callable (ecma_value_t value); +#if JERRY_BUILTIN_PROXY +bool ecma_op_proxy_object_is_callable (ecma_object_t *obj_p); +#endif /* JERRY_BUILTIN_PROXY */ bool ecma_op_object_is_callable (ecma_object_t *obj_p); bool ecma_is_constructor (ecma_value_t value); bool ecma_object_is_constructor (ecma_object_t *obj_p); @@ -92,6 +95,10 @@ ecma_value_t ecma_op_function_has_instance (ecma_object_t *func_obj_p, ecma_value_t value); ecma_value_t +ecma_op_function_validated_call (ecma_value_t callee, ecma_value_t this_arg_value, + const ecma_value_t *arguments_list_p, uint32_t arguments_list_len); + +ecma_value_t ecma_op_function_call (ecma_object_t *func_obj_p, ecma_value_t this_arg_value, const ecma_value_t *arguments_list_p, uint32_t arguments_list_len); diff --git a/jerry-core/ecma/operations/ecma-iterator-object.c b/jerry-core/ecma/operations/ecma-iterator-object.c index cf066d05..badb795e 100644 --- a/jerry-core/ecma/operations/ecma-iterator-object.c +++ b/jerry-core/ecma/operations/ecma-iterator-object.c @@ -248,18 +248,11 @@ ecma_op_get_iterator (ecma_value_t value, /**< value to get iterator from */ } /* 3. */ - if (!ecma_op_is_callable (method)) - { - ecma_free_value (method); - return ecma_raise_type_error (ECMA_ERR_MSG ("Iterator is not function")); - } - - ecma_object_t *method_obj_p = ecma_get_object_from_value (method); - ecma_value_t iterator = ecma_op_function_call (method_obj_p, value, NULL, 0); + ecma_value_t iterator = ecma_op_function_validated_call (method, value, NULL, 0); if (use_default_method) { - ecma_deref_object (method_obj_p); + ecma_free_value (method); } /* 4. */ @@ -284,7 +277,7 @@ ecma_op_get_iterator (ecma_value_t value, /**< value to get iterator from */ return next_method; } - if (ecma_is_value_object (next_method) && ecma_op_is_callable (next_method)) + if (ecma_op_is_callable (next_method)) { *next_method_p = next_method; } @@ -363,15 +356,7 @@ ecma_op_iterator_return (ecma_value_t iterator, /**< iterator value */ return ecma_create_iter_result_object (value, ECMA_VALUE_TRUE); } - if (!ecma_op_is_callable (func_return)) - { - ecma_free_value (func_return); - return ecma_raise_type_error (ECMA_ERR_MSG ("Iterator 'return' is not callable")); - } - - ecma_object_t *return_obj_p = ecma_get_object_from_value (func_return); - - ecma_value_t result = ecma_op_function_call (return_obj_p, iterator, &value, 1); + ecma_value_t result = ecma_op_function_validated_call (func_return, iterator, &value, 1); ecma_free_value (func_return); return result; @@ -415,15 +400,7 @@ ecma_op_iterator_throw (ecma_value_t iterator, /**< iterator value */ return ecma_raise_type_error (ECMA_ERR_MSG ("Iterator 'throw' is not available")); } - if (!ecma_is_value_object (func_throw) || !ecma_op_is_callable (func_throw)) - { - ecma_free_value (func_throw); - return ecma_raise_type_error (ECMA_ERR_MSG ("Iterator 'throw' is not callable")); - } - - ecma_object_t *return_obj_p = ecma_get_object_from_value (func_throw); - - ecma_value_t result = ecma_op_function_call (return_obj_p, iterator, &value, 1); + ecma_value_t result = ecma_op_function_validated_call (func_throw, iterator, &value, 1); ecma_free_value (func_throw); return result; diff --git a/jerry-core/ecma/operations/ecma-objects.c b/jerry-core/ecma/operations/ecma-objects.c index b9b6f358..c096d1b1 100644 --- a/jerry-core/ecma/operations/ecma-objects.c +++ b/jerry-core/ecma/operations/ecma-objects.c @@ -3296,18 +3296,10 @@ ecma_op_invoke (ecma_value_t object, /**< Object value */ } /* 4. */ - if (!ecma_op_is_callable (func)) - { - ecma_free_value (func); - ecma_deref_object (object_p); - return ecma_raise_type_error (ECMA_ERR_MSG ("Argument is not callable")); - } - - ecma_object_t *func_obj_p = ecma_get_object_from_value (func); - ecma_value_t call_result = ecma_op_function_call (func_obj_p, this_arg, args_p, args_len); + ecma_value_t call_result = ecma_op_function_validated_call (func, this_arg, args_p, args_len); + ecma_free_value (func); ecma_deref_object (object_p); - ecma_deref_object (func_obj_p); return call_result; } /* ecma_op_invoke */ diff --git a/jerry-core/ecma/operations/ecma-proxy-object.c b/jerry-core/ecma/operations/ecma-proxy-object.c index 4c22aae1..744805cb 100644 --- a/jerry-core/ecma/operations/ecma-proxy-object.c +++ b/jerry-core/ecma/operations/ecma-proxy-object.c @@ -1771,6 +1771,12 @@ ecma_proxy_object_call (ecma_object_t *obj_p, /**< proxy object */ uint32_t argc) /**< number of arguments */ { JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); + + if (!ecma_op_proxy_object_is_callable (obj_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG (ecma_error_expected_a_function)); + } + ECMA_CHECK_STACK_USAGE (); ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) obj_p; |