Optimize ecma_op_function_call (#4817)

Remove redundant isCallable checks

JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik robert.fancsik@h-lab.eu
This commit is contained in:
Robert Fancsik
2021-11-04 17:26:28 +01:00
committed by GitHub
parent 7ea0000ee0
commit bc091e1742
11 changed files with 326 additions and 371 deletions
+28 -78
View File
@@ -4080,61 +4080,6 @@ jerry_property_descriptor_free (const jerry_property_descriptor_t *prop_desc_p)
} }
} /* jerry_property_descriptor_free */ } /* jerry_property_descriptor_free */
/**
* Invoke function specified by a function value
*
* Note:
* - returned value must be freed with jerry_release_value, when it is no longer needed.
* - If function is invoked as constructor, it should support [[Construct]] method,
* otherwise, if function is simply called - it should support [[Call]] method.
*
* @return returned jerry value of the invoked function
*/
static jerry_value_t
jerry_invoke_function (bool is_invoke_as_constructor, /**< true - invoke function as constructor
* (this_arg_p should be NULL, as it is ignored),
* false - perform function call */
const jerry_value_t func_obj_val, /**< function object to call */
const jerry_value_t this_val, /**< object value of 'this' binding */
const jerry_value_t args_p[], /**< function's call arguments */
const jerry_size_t args_count) /**< number of the arguments */
{
JERRY_ASSERT (args_count == 0 || args_p != NULL);
if (ecma_is_value_error_reference (func_obj_val)
|| ecma_is_value_error_reference (this_val))
{
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (ecma_error_value_msg_p)));
}
for (uint32_t i = 0; i < args_count; i++)
{
if (ecma_is_value_error_reference (args_p[i]))
{
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (ecma_error_value_msg_p)));
}
}
if (is_invoke_as_constructor)
{
JERRY_ASSERT (jerry_value_is_constructor (func_obj_val));
return jerry_return (ecma_op_function_construct (ecma_get_object_from_value (func_obj_val),
ecma_get_object_from_value (func_obj_val),
args_p,
args_count));
}
else
{
JERRY_ASSERT (jerry_value_is_function (func_obj_val));
return jerry_return (ecma_op_function_call (ecma_get_object_from_value (func_obj_val),
this_val,
args_p,
args_count));
}
} /* jerry_invoke_function */
/** /**
* Call function specified by a function value * Call function specified by a function value
* *
@@ -4152,20 +4097,23 @@ jerry_call_function (const jerry_value_t func_obj_val, /**< function object to c
{ {
jerry_assert_api_available (); jerry_assert_api_available ();
if (jerry_value_is_function (func_obj_val) && !ecma_is_value_error_reference (this_val)) if (ecma_is_value_error_reference (this_val))
{ {
for (jerry_size_t i = 0; i < args_count; i++) return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (ecma_error_wrong_args_msg_p)));
{
if (ecma_is_value_error_reference (args_p[i]))
{
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (ecma_error_value_msg_p)));
}
}
return jerry_invoke_function (false, func_obj_val, this_val, args_p, args_count);
} }
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (ecma_error_wrong_args_msg_p))); for (jerry_size_t i = 0; i < args_count; i++)
{
if (ecma_is_value_error_reference (args_p[i]))
{
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (ecma_error_value_msg_p)));
}
}
return jerry_return (ecma_op_function_validated_call (func_obj_val,
this_val,
args_p,
args_count));
} /* jerry_call_function */ } /* jerry_call_function */
/** /**
@@ -4185,21 +4133,23 @@ jerry_construct_object (const jerry_value_t func_obj_val, /**< function object t
{ {
jerry_assert_api_available (); jerry_assert_api_available ();
if (jerry_value_is_constructor (func_obj_val)) if (!jerry_value_is_constructor (func_obj_val))
{ {
for (jerry_size_t i = 0; i < args_count; i++) return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (ecma_error_wrong_args_msg_p)));
{
if (ecma_is_value_error_reference (args_p[i]))
{
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (ecma_error_value_msg_p)));
}
}
ecma_value_t this_val = ECMA_VALUE_UNDEFINED;
return jerry_invoke_function (true, func_obj_val, this_val, args_p, args_count);
} }
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (ecma_error_wrong_args_msg_p))); for (jerry_size_t i = 0; i < args_count; i++)
{
if (ecma_is_value_error_reference (args_p[i]))
{
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (ecma_error_value_msg_p)));
}
}
return jerry_return (ecma_op_function_construct (ecma_get_object_from_value (func_obj_val),
ecma_get_object_from_value (func_obj_val),
args_p,
args_count));
} /* jerry_construct_object */ } /* jerry_construct_object */
/** /**
@@ -241,19 +241,8 @@ ecma_builtin_async_from_sync_iterator_prototype_do (ecma_async_from_sync_iterato
} }
/* 8. */ /* 8. */
ecma_value_t call_result; ecma_value_t call_result = ecma_op_function_validated_call (method, sync_iterator, &call_arg, arg_size);
ecma_free_value (method);
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);
}
/* 9. */ /* 9. */
if (ECMA_IS_VALUE_ERROR (ecma_op_if_abrupt_reject_promise (&call_result, capability_obj_p))) if (ECMA_IS_VALUE_ERROR (ecma_op_if_abrupt_reject_promise (&call_result, capability_obj_p)))
@@ -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_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 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; 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_is_value_undefined (search_symbol) && !ecma_is_value_null (search_symbol))
{ {
if (!ecma_op_is_callable (search_symbol)) ecma_value_t search_result = ecma_op_function_validated_call (search_symbol, regexp_value, &this_value, 1);
{ ecma_free_value (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);
return search_result; 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_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 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; return split_result;
} }
} }
@@ -97,29 +97,21 @@ ecma_async_generator_enqueue (vm_executable_object_t *async_generator_object_p,
static ecma_value_t static ecma_value_t
ecma_async_yield_call (ecma_value_t function, /**< function (takes reference) */ ecma_async_yield_call (ecma_value_t function, /**< function (takes reference) */
vm_executable_object_t *async_generator_object_p, /**< async generator */ vm_executable_object_t *async_generator_object_p, /**< async generator */
ecma_value_t argument, /**< argument passed to the function */ ecma_value_t argument) /**< argument passed to the function */
const char *error_msg_p) /**< error message when the function is not callable */
{ {
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 iterator = async_generator_object_p->iterator;
ecma_value_t result; ecma_value_t result;
if (argument == ECMA_VALUE_EMPTY) 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 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)) 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, result = ecma_async_yield_call (result,
async_generator_object_p, async_generator_object_p,
ECMA_VALUE_EMPTY, ECMA_VALUE_EMPTY);
ECMA_ERR_MSG ("Iterator 'return' is not callable"));
if (ECMA_IS_VALUE_ERROR (result)) 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, result = ecma_async_yield_call (result,
async_generator_object_p, async_generator_object_p,
value, value);
ECMA_ERR_MSG ("Iterator 'throw' is not callable"));
if (ECMA_IS_VALUE_ERROR (result)) 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, result = ecma_async_yield_call (result,
executable_object_p, executable_object_p,
value, value);
ECMA_ERR_MSG ("Iterator 'return' is not callable"));
ecma_free_value (value); ecma_free_value (value);
if (ECMA_IS_VALUE_ERROR (result)) if (ECMA_IS_VALUE_ERROR (result))
+224 -136
View File
@@ -90,6 +90,23 @@ ecma_op_function_form_name (ecma_string_t *prop_name_p, /**< property name */
} /* ecma_op_function_form_name */ } /* ecma_op_function_form_name */
#endif /* JERRY_ESNEXT */ #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. * IsCallable operation.
* *
@@ -108,7 +125,7 @@ ecma_op_object_is_callable (ecma_object_t *obj_p) /**< ecma object */
#if JERRY_BUILTIN_PROXY #if JERRY_BUILTIN_PROXY
if (ECMA_OBJECT_TYPE_IS_PROXY (type)) 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 */ #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; return proto_obj_p;
} /* ecma_op_get_prototype_from_constructor */ } /* 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. * 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 static ecma_value_t
ecma_op_function_call_simple (ecma_object_t *func_obj_p, /**< Function object */ 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 */ const ecma_value_t *arguments_list_p, /**< arguments list */
uint32_t arguments_list_len) /**< length of 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); ext_func_p->u.function.scope_cp);
/* 8. */ /* 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); 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; 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); ecma_global_object_t *realm_p = ecma_op_function_get_realm (bytecode_data_p);
#endif /* JERRY_BUILTIN_REALMS */ #endif /* JERRY_BUILTIN_REALMS */
/* 1. */ /* 5. */
#if JERRY_ESNEXT if (!(status_flags & CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED))
if (JERRY_UNLIKELY (CBC_FUNCTION_IS_ARROW (status_flags)))
{ {
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))
{
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;
} }
else
/* 1. */
switch (CBC_FUNCTION_GET_TYPE (status_flags))
{ {
shared_args.header.status_flags |= VM_FRAME_CTX_SHARED_NON_ARROW_FUNC; #if JERRY_ESNEXT
case CBC_FUNCTION_CONSTRUCTOR:
{
return ecma_op_function_call_constructor (&shared_args, scope_p, this_binding);
}
case CBC_FUNCTION_ARROW:
{
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;
}
#endif /* JERRY_ESNEXT */
default:
{
#if JERRY_ESNEXT
shared_args.header.status_flags |= VM_FRAME_CTX_SHARED_NON_ARROW_FUNC;
#endif /* JERRY_ESNEXT */ #endif /* JERRY_ESNEXT */
if (!(status_flags & CBC_CODE_FLAGS_STRICT_MODE)) if (status_flags & CBC_CODE_FLAGS_STRICT_MODE)
{ {
break;
}
if (ecma_is_value_undefined (this_binding) if (ecma_is_value_undefined (this_binding)
|| ecma_is_value_null (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)); 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 #if JERRY_BUILTIN_REALMS
ecma_global_object_t *saved_global_object_p = JERRY_CONTEXT (global_object_p); ecma_global_object_t *saved_global_object_p = JERRY_CONTEXT (global_object_p);
JERRY_CONTEXT (global_object_p) = realm_p; JERRY_CONTEXT (global_object_p) = realm_p;
#endif /* JERRY_BUILTIN_REALMS */ #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 #if JERRY_BUILTIN_REALMS
JERRY_CONTEXT (global_object_p) = saved_global_object_p; JERRY_CONTEXT (global_object_p) = saved_global_object_p;
#endif /* JERRY_BUILTIN_REALMS */ #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)) if (JERRY_UNLIKELY (shared_args.header.status_flags & VM_FRAME_CTX_SHARED_FREE_LOCAL_ENV))
{ {
ecma_deref_object (scope_p); 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 */ } /* ecma_op_function_call_bound */
/** /**
* [[Call]] implementation for Function objects, * General [[Call]] implementation
* created through 13.2 (ECMA_OBJECT_TYPE_FUNCTION) *
* or 15.3.4.5 (ECMA_OBJECT_TYPE_BOUND_FUNCTION), * @return ecma value
* and for built-in Function objects * Returned value must be freed with ecma_free_value
* from section 15 (ECMA_OBJECT_TYPE_FUNCTION). */
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 * @return ecma value
* Returned value must be freed with ecma_free_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 JERRY_ASSERT (func_obj_p != NULL
&& !ecma_is_lexical_environment (func_obj_p)); && !ecma_is_lexical_environment (func_obj_p));
JERRY_ASSERT (ecma_op_object_is_callable (func_obj_p));
ECMA_CHECK_STACK_USAGE (); 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 #if JERRY_ESNEXT
ecma_object_t *old_new_target_p = JERRY_CONTEXT (current_new_target_p); ecma_object_t *old_new_target_p = JERRY_CONTEXT (current_new_target_p);
if (JERRY_UNLIKELY (!(JERRY_CONTEXT (status_flags) & ECMA_STATUS_DIRECT_EVAL))) if (JERRY_UNLIKELY (!(JERRY_CONTEXT (status_flags) & ECMA_STATUS_DIRECT_EVAL)))
{ {
JERRY_CONTEXT (current_new_target_p) = NULL; 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; ecma_value_t result;
if (JERRY_LIKELY (type == ECMA_OBJECT_TYPE_FUNCTION)) switch (ecma_get_object_type (func_obj_p))
{ {
result = ecma_op_function_call_simple (func_obj_p, this_arg_value, arguments_list_p, arguments_list_len); case ECMA_OBJECT_TYPE_FUNCTION:
} {
else if (type == ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION) result = ecma_op_function_call_simple (func_obj_p, this_arg_value, arguments_list_p, arguments_list_len);
{ break;
result = ecma_op_function_call_native_built_in (func_obj_p, this_arg_value, arguments_list_p, arguments_list_len); }
} case ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION:
else if (type == ECMA_OBJECT_TYPE_NATIVE_FUNCTION) {
{ result = ecma_op_function_call_native_built_in (func_obj_p, this_arg_value, arguments_list_p, arguments_list_len);
result = ecma_op_function_call_native (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 #if JERRY_ESNEXT
else if (JERRY_UNLIKELY (type == ECMA_OBJECT_TYPE_CONSTRUCTOR_FUNCTION)) case ECMA_OBJECT_TYPE_CONSTRUCTOR_FUNCTION:
{ {
result = ecma_raise_type_error (ECMA_ERR_MSG (ecma_error_class_constructor_new)); result = ecma_raise_type_error (ECMA_ERR_MSG (ecma_error_class_constructor_new));
} break;
}
#endif /* JERRY_ESNEXT */ #endif /* JERRY_ESNEXT */
else case ECMA_OBJECT_TYPE_NATIVE_FUNCTION:
{ {
result = ecma_op_function_call_bound (func_obj_p, arguments_list_p, arguments_list_len); 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 #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 JERRY_ASSERT (func_obj_p != NULL
&& !ecma_is_lexical_environment (func_obj_p)); && !ecma_is_lexical_environment (func_obj_p));
const ecma_object_type_t type = ecma_get_object_type (func_obj_p); switch (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); case 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) }
{ 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); {
} return ecma_op_function_construct_built_in (func_obj_p, new_target_p, arguments_list_p, arguments_list_len);
}
#if JERRY_BUILTIN_PROXY #if JERRY_BUILTIN_PROXY
if (ECMA_OBJECT_TYPE_IS_PROXY (type)) case ECMA_OBJECT_TYPE_PROXY:
{ {
return ecma_proxy_object_construct (func_obj_p, new_target_p, arguments_list_p, arguments_list_len); return ecma_proxy_object_construct (func_obj_p, new_target_p, arguments_list_p, arguments_list_len);
} }
#endif /* JERRY_BUILTIN_PROXY */ #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 JERRY_ESNEXT
if (type == ECMA_OBJECT_TYPE_CONSTRUCTOR_FUNCTION) case ECMA_OBJECT_TYPE_CONSTRUCTOR_FUNCTION:
{ {
return ecma_op_function_construct_constructor (func_obj_p, new_target_p, arguments_list_p, arguments_list_len); return ecma_op_function_construct_constructor (func_obj_p, new_target_p, arguments_list_p, arguments_list_len);
} }
#endif /* JERRY_ESNEXT */ #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_VALUE_UNDEFINED;
return ecma_op_function_construct_native (func_obj_p, new_target_p, arguments_list_p, arguments_list_len);
} /* ecma_op_function_construct */ } /* ecma_op_function_construct */
/** /**
@@ -33,6 +33,9 @@ ecma_value_t ecma_op_function_form_name (ecma_string_t *prop_name_p, char *prefi
#endif /* JERRY_ESNEXT */ #endif /* JERRY_ESNEXT */
bool ecma_op_is_callable (ecma_value_t value); 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_op_object_is_callable (ecma_object_t *obj_p);
bool ecma_is_constructor (ecma_value_t value); bool ecma_is_constructor (ecma_value_t value);
bool ecma_object_is_constructor (ecma_object_t *obj_p); bool ecma_object_is_constructor (ecma_object_t *obj_p);
@@ -91,6 +94,10 @@ ecma_op_get_prototype_from_constructor (ecma_object_t *ctor_obj_p, ecma_builtin_
ecma_value_t ecma_value_t
ecma_op_function_has_instance (ecma_object_t *func_obj_p, ecma_value_t value); 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_value_t
ecma_op_function_call (ecma_object_t *func_obj_p, ecma_value_t this_arg_value, 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); const ecma_value_t *arguments_list_p, uint32_t arguments_list_len);
@@ -248,18 +248,11 @@ ecma_op_get_iterator (ecma_value_t value, /**< value to get iterator from */
} }
/* 3. */ /* 3. */
if (!ecma_op_is_callable (method)) ecma_value_t iterator = ecma_op_function_validated_call (method, value, NULL, 0);
{
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);
if (use_default_method) if (use_default_method)
{ {
ecma_deref_object (method_obj_p); ecma_free_value (method);
} }
/* 4. */ /* 4. */
@@ -284,7 +277,7 @@ ecma_op_get_iterator (ecma_value_t value, /**< value to get iterator from */
return next_method; 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; *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); return ecma_create_iter_result_object (value, ECMA_VALUE_TRUE);
} }
if (!ecma_op_is_callable (func_return)) ecma_value_t result = ecma_op_function_validated_call (func_return, iterator, &value, 1);
{
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_free_value (func_return); ecma_free_value (func_return);
return result; 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")); 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_value_t result = ecma_op_function_validated_call (func_throw, iterator, &value, 1);
{
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_free_value (func_throw); ecma_free_value (func_throw);
return result; return result;
+2 -10
View File
@@ -3296,18 +3296,10 @@ ecma_op_invoke (ecma_value_t object, /**< Object value */
} }
/* 4. */ /* 4. */
if (!ecma_op_is_callable (func)) ecma_value_t call_result = ecma_op_function_validated_call (func, this_arg, args_p, args_len);
{ ecma_free_value (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_deref_object (object_p); ecma_deref_object (object_p);
ecma_deref_object (func_obj_p);
return call_result; return call_result;
} /* ecma_op_invoke */ } /* ecma_op_invoke */
@@ -1771,6 +1771,12 @@ ecma_proxy_object_call (ecma_object_t *obj_p, /**< proxy object */
uint32_t argc) /**< number of arguments */ uint32_t argc) /**< number of arguments */
{ {
JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); 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_CHECK_STACK_USAGE ();
ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) obj_p; ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) obj_p;
+35 -43
View File
@@ -380,58 +380,50 @@ vm_stack_find_finally (vm_frame_ctx_t *frame_ctx_p, /**< frame context */
if (!ECMA_IS_VALUE_ERROR (result) && !ecma_is_value_undefined (result)) if (!ECMA_IS_VALUE_ERROR (result) && !ecma_is_value_undefined (result))
{ {
if (!ecma_op_is_callable (result)) ecma_object_t *return_obj_p = ecma_get_object_from_value (result);
result = ecma_op_function_validated_call (result, iterator, NULL, 0);
ecma_deref_object (return_obj_p);
if (context_type == VM_CONTEXT_FOR_AWAIT_OF && !ECMA_IS_VALUE_ERROR (result))
{ {
ecma_free_value (result); ecma_extended_object_t *async_generator_object_p = VM_GET_EXECUTABLE_OBJECT (frame_ctx_p);
result = ecma_raise_type_error (ECMA_ERR_MSG ("Iterator 'return' is not callable"));
}
else
{
ecma_object_t *return_obj_p = ecma_get_object_from_value (result);
result = ecma_op_function_call (return_obj_p, iterator, NULL, 0);
ecma_deref_object (return_obj_p);
if (context_type == VM_CONTEXT_FOR_AWAIT_OF && !ECMA_IS_VALUE_ERROR (result)) result = ecma_promise_async_await (async_generator_object_p, result);
{
ecma_extended_object_t *async_generator_object_p = VM_GET_EXECUTABLE_OBJECT (frame_ctx_p);
result = ecma_promise_async_await (async_generator_object_p, result);
if (!ECMA_IS_VALUE_ERROR (result))
{
uint16_t extra_flags = (ECMA_EXECUTABLE_OBJECT_DO_AWAIT_OR_YIELD
| (ECMA_AWAIT_FOR_CLOSE << ECMA_AWAIT_STATE_SHIFT));
async_generator_object_p->u.cls.u2.executable_obj_flags |= extra_flags;
stack_top_p = vm_stack_context_abort (frame_ctx_p, stack_top_p);
VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_FINALLY_CONTEXT_STACK_ALLOCATION);
stack_top_p += PARSER_FINALLY_CONTEXT_STACK_ALLOCATION;
stack_top_p[-1] = VM_CREATE_CONTEXT ((uint32_t) finally_type, context_end);
if (finally_type == VM_CONTEXT_FINALLY_THROW)
{
stack_top_p[-2] = exception;
}
frame_ctx_p->call_operation = VM_EXEC_RETURN;
frame_ctx_p->byte_code_p = vm_stack_resume_executable_object_with_context_end;
frame_ctx_p->stack_top_p = stack_top_p;
return VM_CONTEXT_FOUND_AWAIT;
}
}
if (!ECMA_IS_VALUE_ERROR (result)) if (!ECMA_IS_VALUE_ERROR (result))
{ {
bool is_object = ecma_is_value_object (result); uint16_t extra_flags = (ECMA_EXECUTABLE_OBJECT_DO_AWAIT_OR_YIELD
| (ECMA_AWAIT_FOR_CLOSE << ECMA_AWAIT_STATE_SHIFT));
async_generator_object_p->u.cls.u2.executable_obj_flags |= extra_flags;
ecma_free_value (result); stack_top_p = vm_stack_context_abort (frame_ctx_p, stack_top_p);
result = ECMA_VALUE_UNDEFINED;
if (!is_object) VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_FINALLY_CONTEXT_STACK_ALLOCATION);
stack_top_p += PARSER_FINALLY_CONTEXT_STACK_ALLOCATION;
stack_top_p[-1] = VM_CREATE_CONTEXT ((uint32_t) finally_type, context_end);
if (finally_type == VM_CONTEXT_FINALLY_THROW)
{ {
result = ecma_raise_type_error (ECMA_ERR_MSG ("Iterator 'return' result is not object")); stack_top_p[-2] = exception;
} }
frame_ctx_p->call_operation = VM_EXEC_RETURN;
frame_ctx_p->byte_code_p = vm_stack_resume_executable_object_with_context_end;
frame_ctx_p->stack_top_p = stack_top_p;
return VM_CONTEXT_FOUND_AWAIT;
}
}
if (!ECMA_IS_VALUE_ERROR (result))
{
bool is_object = ecma_is_value_object (result);
ecma_free_value (result);
result = ECMA_VALUE_UNDEFINED;
if (!is_object)
{
result = ecma_raise_type_error (ECMA_ERR_MSG ("Iterator 'return' result is not object"));
} }
} }
} }
+4 -15
View File
@@ -788,22 +788,11 @@ opfunc_call (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
ecma_value_t *stack_top_p = frame_ctx_p->stack_top_p - arguments_list_len; ecma_value_t *stack_top_p = frame_ctx_p->stack_top_p - arguments_list_len;
ecma_value_t this_value = is_call_prop ? stack_top_p[-3] : ECMA_VALUE_UNDEFINED; ecma_value_t this_value = is_call_prop ? stack_top_p[-3] : ECMA_VALUE_UNDEFINED;
ecma_value_t func_value = stack_top_p[-1]; ecma_value_t func_value = stack_top_p[-1];
ecma_value_t completion_value;
if (!ecma_is_value_object (func_value) ecma_value_t completion_value = ecma_op_function_validated_call (func_value,
|| !ecma_op_object_is_callable (ecma_get_object_from_value (func_value))) this_value,
{ stack_top_p,
completion_value = ecma_raise_type_error (ECMA_ERR_MSG (ecma_error_expected_a_function)); arguments_list_len);
}
else
{
ecma_object_t *func_obj_p = ecma_get_object_from_value (func_value);
completion_value = ecma_op_function_call (func_obj_p,
this_value,
stack_top_p,
arguments_list_len);
}
JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_DIRECT_EVAL; JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_DIRECT_EVAL;