Files
jerryscript/jerry-core/ecma/operations/ecma-function-object.c
T
Dániel Bátyai 9860d66a56 Rework the public API (#4829)
Related to #4186.

Some notable changes:
  - The term 'Error' now strictly refers to native Error objects defined in
    the ECMA standard, which are ordinary objects. All other uses of
    'error' or 'error reference' where the term refers to a thrown value is
    now called 'exception'.

  - Simplified the naming scheme of many String API functions. These functions
    will now also take an 'encoding' argument to specify the desired
    encoding in which to operate.

  - Removed the substring-copy-to-buffer functions. These functions
    behaved awkwardly, as they use character index to specify the
    start/end positions, and were mostly used incorrectly with byte
    offsets instead. The functionality can still be replicated with
    other functions if necessary.

  - String-to-buffer functions will no longer fail if the buffer is not
    sufficiently large, the string will instead be cropped.

  - Fixed the usage of the '_sz' prefix in many API functions. The term
    'sz' means zero-terminated string in hungarian notation, this was
    used incorrectly in many cases.

  - Renamed most of the public API functions to have shorter, more on-point
    names, rather than the often too long descriptive names. Functions are now
    also grouped by the type of value they operate on, where this makes
    sense.

JerryScript-DCO-1.0-Signed-off-by: Dániel Bátyai dbatyai@inf.u-szeged.hu
2021-12-06 10:20:09 +01:00

2351 lines
78 KiB
C

/* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecma-function-object.h"
#include "ecma-alloc.h"
#include "ecma-builtin-handlers.h"
#include "ecma-builtin-helpers.h"
#include "ecma-errors.h"
#include "ecma-exceptions.h"
#include "ecma-extended-info.h"
#include "ecma-gc.h"
#include "ecma-helpers.h"
#include "ecma-lex-env.h"
#include "ecma-objects-general.h"
#include "ecma-objects.h"
#include "ecma-promise-object.h"
#include "ecma-proxy-object.h"
#include "ecma-symbol-object.h"
#include "jcontext.h"
#include "lit-char-helpers.h"
#include "opcodes.h"
/** \addtogroup ecma ECMA
* @{
*
* \addtogroup ecmafunctionobject ECMA Function object related routines
* @{
*/
#if JERRY_ESNEXT
/**
* SetFunctionName operation
*
* See also: ECMAScript v6, 9.2.1.1
*
* @return resource name as ecma-string
*/
ecma_value_t
ecma_op_function_form_name (ecma_string_t *prop_name_p, /**< property name */
char *prefix_p, /**< prefix */
lit_utf8_size_t prefix_size) /**< prefix length */
{
/* 4. */
if (ecma_prop_name_is_symbol (prop_name_p))
{
/* .a */
ecma_value_t string_desc = ecma_get_symbol_description (prop_name_p);
/* .b */
if (ecma_is_value_undefined (string_desc))
{
prop_name_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);
}
/* .c */
else
{
ecma_string_t *string_desc_p = ecma_get_string_from_value (string_desc);
ecma_stringbuilder_t builder = ecma_stringbuilder_create_raw ((lit_utf8_byte_t *) "[", 1);
ecma_stringbuilder_append (&builder, string_desc_p);
ecma_stringbuilder_append_byte (&builder, (lit_utf8_byte_t) LIT_CHAR_RIGHT_SQUARE);
prop_name_p = ecma_stringbuilder_finalize (&builder);
}
}
else
{
ecma_ref_ecma_string (prop_name_p);
}
/* 5. */
if (JERRY_UNLIKELY (prefix_p != NULL))
{
ecma_stringbuilder_t builder = ecma_stringbuilder_create_raw ((lit_utf8_byte_t *) prefix_p, prefix_size);
ecma_stringbuilder_append (&builder, prop_name_p);
ecma_deref_ecma_string (prop_name_p);
prop_name_p = ecma_stringbuilder_finalize (&builder);
}
return ecma_make_string_value (prop_name_p);
} /* 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.
*
* See also: ECMA-262 v5, 9.11
*
* @return true - if the given object is callable;
* false - otherwise
*/
extern inline bool JERRY_ATTR_ALWAYS_INLINE
ecma_op_object_is_callable (ecma_object_t *obj_p) /**< ecma object */
{
JERRY_ASSERT (!ecma_is_lexical_environment (obj_p));
const ecma_object_type_t type = ecma_get_object_type (obj_p);
#if JERRY_BUILTIN_PROXY
if (ECMA_OBJECT_TYPE_IS_PROXY (type))
{
return ecma_op_proxy_object_is_callable (obj_p);
}
#endif /* JERRY_BUILTIN_PROXY */
return type >= ECMA_OBJECT_TYPE_FUNCTION;
} /* ecma_op_object_is_callable */
/**
* IsCallable operation.
*
* See also: ECMA-262 v5, 9.11
*
* @return true - if value is callable object;
* false - otherwise
*/
bool
ecma_op_is_callable (ecma_value_t value) /**< ecma value */
{
return (ecma_is_value_object (value) && ecma_op_object_is_callable (ecma_get_object_from_value (value)));
} /* ecma_op_is_callable */
/**
* Implement IsConstructor abstract operation.
*
*
* @return ECMA_IS_VALID_CONSTRUCTOR - if object is a valid for constructor call
* ecma_error_msg_t id of error - otherwise
*/
ecma_error_msg_t
ecma_object_check_constructor (ecma_object_t *obj_p) /**< ecma object */
{
JERRY_ASSERT (!ecma_is_lexical_environment (obj_p));
ecma_object_type_t type = ecma_get_object_type (obj_p);
if (JERRY_UNLIKELY (type < ECMA_OBJECT_TYPE_PROXY))
{
return ECMA_ERR_INVALID_TYPE_FOR_CONSTRUCTOR_CALL;
}
while (JERRY_UNLIKELY (type == ECMA_OBJECT_TYPE_BOUND_FUNCTION))
{
ecma_bound_function_t *bound_func_p = (ecma_bound_function_t *) obj_p;
obj_p =
ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t, bound_func_p->header.u.bound_function.target_function);
type = ecma_get_object_type (obj_p);
}
if (JERRY_LIKELY (type == ECMA_OBJECT_TYPE_FUNCTION))
{
#if JERRY_ESNEXT
const ecma_compiled_code_t *byte_code_p = ecma_op_function_get_compiled_code ((ecma_extended_object_t *) obj_p);
if (!CBC_FUNCTION_IS_CONSTRUCTABLE (byte_code_p->status_flags))
{
#if JERRY_ERROR_MESSAGES
switch (CBC_FUNCTION_GET_TYPE (byte_code_p->status_flags))
{
case CBC_FUNCTION_SCRIPT:
{
return ECMA_ERR_SCRIPT_GLOBAL_FUNCTIONS_INVOKE_WITH_NEW;
}
case CBC_FUNCTION_GENERATOR:
{
return ECMA_ERR_GENERATOR_FUNCTIONS_INVOKE_WITH_NEW;
}
case CBC_FUNCTION_ASYNC:
{
return ECMA_ERR_ASYNC_FUNCTIONS_INVOKE_WITH_NEW;
}
case CBC_FUNCTION_ASYNC_GENERATOR:
{
return ECMA_ERR_ASYNC_GENERATOR_FUNCTIONS_INVOKE_WITH_NEW;
}
case CBC_FUNCTION_ACCESSOR:
{
return ECMA_ERR_ACCESSOR_FUNCTIONS_INVOKE_WITH_NEW;
}
case CBC_FUNCTION_METHOD:
{
return ECMA_ERR_METHODS_INVOKE_WITH_NEW;
}
case CBC_FUNCTION_ARROW:
{
return ECMA_ERR_ARROW_FUNCTIONS_INVOKE_WITH_NEW;
}
default:
{
JERRY_ASSERT (CBC_FUNCTION_GET_TYPE (byte_code_p->status_flags) == CBC_FUNCTION_ASYNC_ARROW);
return ECMA_ERR_ASYNC_ARROW_FUNCTIONS_INVOKE_WITH_NEW;
}
}
#else /* !JERRY_ERROR_MESSAGES */
return ECMA_ERR_EMPTY;
#endif /* JERRY_ERROR_MESSAGES */
}
#endif /* JERRY_NEXT */
return ECMA_IS_VALID_CONSTRUCTOR;
}
#if JERRY_BUILTIN_PROXY
if (ECMA_OBJECT_TYPE_IS_PROXY (type))
{
if (!(obj_p->u2.prototype_cp & ECMA_PROXY_IS_CONSTRUCTABLE))
{
return ECMA_ERR_PROXY_TARGET_IS_NOT_A_CONSTRUCTOR;
}
return ECMA_IS_VALID_CONSTRUCTOR;
}
#endif /* JERRY_BUILTIN_PROXY */
JERRY_ASSERT (type == ECMA_OBJECT_TYPE_NATIVE_FUNCTION || type == ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION
|| type == ECMA_OBJECT_TYPE_CONSTRUCTOR_FUNCTION);
if (type == ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION)
{
if (ecma_builtin_function_is_routine (obj_p))
{
return ECMA_ERR_BULTIN_ROUTINES_HAVE_NO_CONSTRUCTOR;
}
#if JERRY_ESNEXT
JERRY_ASSERT (((ecma_extended_object_t *) obj_p)->u.built_in.id != ECMA_BUILTIN_ID_HANDLER);
#endif /* !JERRY_ESNEXT */
}
return ECMA_IS_VALID_CONSTRUCTOR;
} /* ecma_object_check_constructor */
/**
* Implement IsConstructor abstract operation.
*
* @return ECMA_IS_VALID_CONSTRUCTOR - if the input value is a constructor.
* ecma_error_msg_t id of error - otherwise
*/
extern inline ecma_error_msg_t JERRY_ATTR_ALWAYS_INLINE
ecma_check_constructor (ecma_value_t value) /**< ecma object */
{
if (!ecma_is_value_object (value))
{
return ECMA_ERR_INVALID_TYPE_FOR_CONSTRUCTOR_CALL;
}
return ecma_object_check_constructor (ecma_get_object_from_value (value));
} /* ecma_check_constructor */
/**
* Checks whether the given object implements [[Construct]].
*
* @return true - if the given object is constructor;
* false - otherwise
*/
extern inline bool JERRY_ATTR_ALWAYS_INLINE
ecma_object_is_constructor (ecma_object_t *obj_p) /**< ecma object */
{
return ecma_object_check_constructor (obj_p) == ECMA_IS_VALID_CONSTRUCTOR;
} /* ecma_object_is_constructor */
/**
* Checks whether the value is Object that implements [[Construct]].
*
* @return true - if value is constructor object;
* false - otherwise
*/
bool
ecma_is_constructor (ecma_value_t value) /**< ecma value */
{
return (ecma_is_value_object (value) && ecma_object_is_constructor (ecma_get_object_from_value (value)));
} /* ecma_is_constructor */
/**
* Helper method to count and convert the arguments for the Function/GeneratorFunction constructor call.
*
* See also:
* ECMA 262 v5.1 15.3.2.1 steps 5.a-d
* ECMA 262 v6 19.2.1.1.1 steps 8
*
* @return ecma value - concatenated arguments as a string.
* Returned value must be freed with ecma_free_value.
*/
static ecma_string_t *
ecma_op_create_dynamic_function_arguments_helper (const ecma_value_t *arguments_list_p, /**< arguments list */
uint32_t arguments_list_len) /**< number of arguments */
{
JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);
if (arguments_list_len <= 1)
{
return ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);
}
ecma_string_t *str_p = ecma_op_to_string (arguments_list_p[0]);
if (JERRY_UNLIKELY (str_p == NULL))
{
return str_p;
}
if (arguments_list_len == 2)
{
return str_p;
}
ecma_stringbuilder_t builder = ecma_stringbuilder_create_from (str_p);
ecma_deref_ecma_string (str_p);
for (uint32_t idx = 1; idx < arguments_list_len - 1; idx++)
{
str_p = ecma_op_to_string (arguments_list_p[idx]);
if (JERRY_UNLIKELY (str_p == NULL))
{
ecma_stringbuilder_destroy (&builder);
return str_p;
}
ecma_stringbuilder_append_char (&builder, LIT_CHAR_COMMA);
ecma_stringbuilder_append (&builder, str_p);
ecma_deref_ecma_string (str_p);
}
return ecma_stringbuilder_finalize (&builder);
} /* ecma_op_create_dynamic_function_arguments_helper */
/**
* Function object creation operation.
*
* See also: ECMA-262 v5, 13.2
*
* @return pointer to newly created Function object
*/
static ecma_object_t *
ecma_op_create_function_object (ecma_object_t *scope_p, /**< function's scope */
const ecma_compiled_code_t *bytecode_data_p, /**< byte-code array */
ecma_builtin_id_t proto_id) /**< builtin id of the prototype object */
{
JERRY_ASSERT (ecma_is_lexical_environment (scope_p));
/* 1., 4., 13. */
ecma_object_t *prototype_obj_p = ecma_builtin_get (proto_id);
size_t function_object_size = sizeof (ecma_extended_object_t);
#if JERRY_SNAPSHOT_EXEC
if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)
{
function_object_size = sizeof (ecma_static_function_t);
}
#endif /* JERRY_SNAPSHOT_EXEC */
ecma_object_t *func_p = ecma_create_object (prototype_obj_p, function_object_size, ECMA_OBJECT_TYPE_FUNCTION);
/* 2., 6., 7., 8. */
/*
* We don't setup [[Get]], [[Call]], [[Construct]], [[HasInstance]] for each function object.
* Instead we set the object's type to ECMA_OBJECT_TYPE_FUNCTION
* that defines which version of the routine should be used on demand.
*/
/* 3. */
/*
* [[Class]] property is not stored explicitly for objects of ECMA_OBJECT_TYPE_FUNCTION type.
*
* See also: ecma_object_get_class_name
*/
ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) func_p;
/* 9. */
ECMA_SET_NON_NULL_POINTER_TAG (ext_func_p->u.function.scope_cp, scope_p, 0);
/* 10., 11., 12. */
#if JERRY_SNAPSHOT_EXEC
if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)
{
ext_func_p->u.function.bytecode_cp = JMEM_CP_NULL;
((ecma_static_function_t *) func_p)->bytecode_p = bytecode_data_p;
}
else
#endif /* JERRY_SNAPSHOT_EXEC */
{
ECMA_SET_INTERNAL_VALUE_POINTER (ext_func_p->u.function.bytecode_cp, bytecode_data_p);
ecma_bytecode_ref ((ecma_compiled_code_t *) bytecode_data_p);
}
/* 14., 15., 16., 17., 18. */
/*
* 'length' and 'prototype' properties are instantiated lazily
*
* See also: ecma_op_function_try_to_lazy_instantiate_property
*/
return func_p;
} /* ecma_op_create_function_object */
/**
* CreateDynamicFunction operation
*
* See also:
* ECMA-262 v5, 15.3.
* ECMA-262 v6, 19.2.1.1
*
* @return ECMA_VALUE_ERROR - if the operation fails
* constructed function object - otherwise
*/
ecma_value_t
ecma_op_create_dynamic_function (const ecma_value_t *arguments_list_p, /**< arguments list */
uint32_t arguments_list_len, /**< number of arguments */
ecma_parse_opts_t parse_opts) /**< parse options */
{
JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);
ecma_string_t *arguments_str_p =
ecma_op_create_dynamic_function_arguments_helper (arguments_list_p, arguments_list_len);
if (JERRY_UNLIKELY (arguments_str_p == NULL))
{
return ECMA_VALUE_ERROR;
}
ecma_string_t *function_body_str_p;
if (arguments_list_len > 0)
{
function_body_str_p = ecma_op_to_string (arguments_list_p[arguments_list_len - 1]);
if (JERRY_UNLIKELY (function_body_str_p == NULL))
{
ecma_deref_ecma_string (arguments_str_p);
return ECMA_VALUE_ERROR;
}
}
else
{
/* Very unlikely code path, not optimized. */
function_body_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);
}
ecma_value_t source[2];
source[0] = ecma_make_string_value (function_body_str_p);
source[1] = ecma_make_string_value (arguments_str_p);
parse_opts |= ECMA_PARSE_HAS_SOURCE_VALUE | ECMA_PARSE_HAS_ARGUMENT_LIST_VALUE;
ecma_compiled_code_t *bytecode_p = parser_parse_script ((void *) source, parse_opts, NULL);
ecma_deref_ecma_string (arguments_str_p);
ecma_deref_ecma_string (function_body_str_p);
if (JERRY_UNLIKELY (bytecode_p == NULL))
{
return ECMA_VALUE_ERROR;
}
#if JERRY_ESNEXT
ecma_value_t *func_name_p;
func_name_p = ecma_compiled_code_resolve_function_name ((const ecma_compiled_code_t *) bytecode_p);
*func_name_p = ecma_make_magic_string_value (LIT_MAGIC_STRING_ANONYMOUS);
#endif /* JERRY_ESNEXT */
ecma_object_t *global_object_p = ecma_builtin_get_global ();
#if JERRY_BUILTIN_REALMS
JERRY_ASSERT (global_object_p == (ecma_object_t *) ecma_op_function_get_realm (bytecode_p));
#endif /* JERRY_BUILTIN_REALMS */
ecma_object_t *global_env_p = ecma_get_global_environment (global_object_p);
ecma_builtin_id_t fallback_proto = ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE;
#if JERRY_ESNEXT
ecma_object_t *new_target_p = JERRY_CONTEXT (current_new_target_p);
ecma_builtin_id_t fallback_ctor = ECMA_BUILTIN_ID_FUNCTION;
if (JERRY_UNLIKELY (parse_opts & (ECMA_PARSE_GENERATOR_FUNCTION | ECMA_PARSE_ASYNC_FUNCTION)))
{
fallback_proto = ECMA_BUILTIN_ID_ASYNC_GENERATOR;
fallback_ctor = ECMA_BUILTIN_ID_ASYNC_GENERATOR_FUNCTION;
if (!(parse_opts & ECMA_PARSE_GENERATOR_FUNCTION))
{
fallback_proto = ECMA_BUILTIN_ID_ASYNC_FUNCTION_PROTOTYPE;
fallback_ctor = ECMA_BUILTIN_ID_ASYNC_FUNCTION;
}
else if (!(parse_opts & ECMA_PARSE_ASYNC_FUNCTION))
{
fallback_proto = ECMA_BUILTIN_ID_GENERATOR;
fallback_ctor = ECMA_BUILTIN_ID_GENERATOR_FUNCTION;
}
}
if (new_target_p == NULL)
{
new_target_p = ecma_builtin_get (fallback_ctor);
}
ecma_object_t *proto = ecma_op_get_prototype_from_constructor (new_target_p, fallback_proto);
if (JERRY_UNLIKELY (proto == NULL))
{
ecma_bytecode_deref (bytecode_p);
return ECMA_VALUE_ERROR;
}
#endif /* JERRY_ESNEXT */
ecma_object_t *func_obj_p = ecma_op_create_function_object (global_env_p, bytecode_p, fallback_proto);
#if JERRY_ESNEXT
ECMA_SET_NON_NULL_POINTER (func_obj_p->u2.prototype_cp, proto);
ecma_deref_object (proto);
#endif /* JERRY_ESNEXT */
ecma_bytecode_deref (bytecode_p);
return ecma_make_object_value (func_obj_p);
} /* ecma_op_create_dynamic_function */
/**
* Function object creation operation.
*
* See also: ECMA-262 v5, 13.2
*
* @return pointer to newly created Function object
*/
ecma_object_t *
ecma_op_create_simple_function_object (ecma_object_t *scope_p, /**< function's scope */
const ecma_compiled_code_t *bytecode_data_p) /**< byte-code array */
{
return ecma_op_create_function_object (scope_p, bytecode_data_p, ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE);
} /* ecma_op_create_simple_function_object */
#if JERRY_ESNEXT
/**
* Create a function object with the appropriate prototype.
*
* @return pointer to newly created Function object
*/
ecma_object_t *
ecma_op_create_any_function_object (ecma_object_t *scope_p, /**< function's scope */
const ecma_compiled_code_t *bytecode_data_p) /**< byte-code array */
{
ecma_builtin_id_t proto_id;
switch (CBC_FUNCTION_GET_TYPE (bytecode_data_p->status_flags))
{
case CBC_FUNCTION_GENERATOR:
{
proto_id = ECMA_BUILTIN_ID_GENERATOR;
break;
}
case CBC_FUNCTION_ASYNC:
{
proto_id = ECMA_BUILTIN_ID_ASYNC_FUNCTION_PROTOTYPE;
break;
}
case CBC_FUNCTION_ASYNC_GENERATOR:
{
proto_id = ECMA_BUILTIN_ID_ASYNC_GENERATOR;
break;
}
default:
{
proto_id = ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE;
break;
}
}
return ecma_op_create_function_object (scope_p, bytecode_data_p, proto_id);
} /* ecma_op_create_any_function_object */
/**
* Arrow function object creation operation.
*
* See also: ES2015, 9.2.12
*
* @return pointer to newly created Function object
*/
ecma_object_t *
ecma_op_create_arrow_function_object (ecma_object_t *scope_p, /**< function's scope */
const ecma_compiled_code_t *bytecode_data_p, /**< byte-code array */
ecma_value_t this_binding) /**< value of 'this' binding */
{
ecma_object_t *prototype_obj_p;
if (CBC_FUNCTION_GET_TYPE (bytecode_data_p->status_flags) == CBC_FUNCTION_ARROW)
{
prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE);
}
else
{
JERRY_ASSERT (CBC_FUNCTION_GET_TYPE (bytecode_data_p->status_flags) == CBC_FUNCTION_ASYNC_ARROW);
prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_ASYNC_FUNCTION_PROTOTYPE);
}
size_t arrow_function_object_size = sizeof (ecma_arrow_function_t);
#if JERRY_SNAPSHOT_EXEC
if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)
{
arrow_function_object_size = sizeof (ecma_static_arrow_function_t);
}
#endif /* JERRY_SNAPSHOT_EXEC */
ecma_object_t *func_p = ecma_create_object (prototype_obj_p, arrow_function_object_size, ECMA_OBJECT_TYPE_FUNCTION);
ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) func_p;
ECMA_SET_NON_NULL_POINTER_TAG (arrow_func_p->header.u.function.scope_cp, scope_p, 0);
#if JERRY_SNAPSHOT_EXEC
if ((bytecode_data_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION))
{
arrow_func_p->header.u.function.bytecode_cp = ECMA_NULL_POINTER;
((ecma_static_arrow_function_t *) func_p)->bytecode_p = bytecode_data_p;
}
else
{
#endif /* JERRY_SNAPSHOT_EXEC */
ECMA_SET_INTERNAL_VALUE_POINTER (arrow_func_p->header.u.function.bytecode_cp, bytecode_data_p);
ecma_bytecode_ref ((ecma_compiled_code_t *) bytecode_data_p);
#if JERRY_SNAPSHOT_EXEC
}
#endif /* JERRY_SNAPSHOT_EXEC */
arrow_func_p->this_binding = ecma_copy_value_if_not_object (this_binding);
arrow_func_p->new_target = ECMA_VALUE_UNDEFINED;
if (JERRY_CONTEXT (current_new_target_p) != NULL)
{
arrow_func_p->new_target = ecma_make_object_value (JERRY_CONTEXT (current_new_target_p));
}
return func_p;
} /* ecma_op_create_arrow_function_object */
#endif /* JERRY_ESNEXT */
/**
* External function object creation operation.
*
* Note:
* external function object is implementation-defined object type
* that represent functions implemented in native code, using Embedding API
*
* @return pointer to newly created external function object
*/
ecma_object_t *
ecma_op_create_external_function_object (ecma_native_handler_t handler_cb) /**< pointer to external native handler */
{
ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE);
ecma_object_t *function_obj_p =
ecma_create_object (prototype_obj_p, sizeof (ecma_native_function_t), ECMA_OBJECT_TYPE_NATIVE_FUNCTION);
/*
* [[Class]] property is not stored explicitly for objects of ECMA_OBJECT_TYPE_NATIVE_FUNCTION type.
*
* See also: ecma_object_get_class_name
*/
ecma_native_function_t *native_function_p = (ecma_native_function_t *) function_obj_p;
#if JERRY_BUILTIN_REALMS
ECMA_SET_INTERNAL_VALUE_POINTER (native_function_p->realm_value, ecma_builtin_get_global ());
#endif /* JERRY_BUILTIN_REALMS */
native_function_p->native_handler_cb = handler_cb;
return function_obj_p;
} /* ecma_op_create_external_function_object */
#if JERRY_ESNEXT
/**
* Create built-in native handler object.
*
* @return pointer to newly created native handler object
*/
ecma_object_t *
ecma_op_create_native_handler (ecma_native_handler_id_t id, /**< handler id */
size_t object_size) /**< created object size */
{
ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE);
ecma_object_t *function_obj_p = ecma_create_object (prototype_obj_p, object_size, ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION);
ecma_extended_object_t *ext_func_obj_p = (ecma_extended_object_t *) function_obj_p;
ext_func_obj_p->u.built_in.id = ECMA_BUILTIN_ID_HANDLER;
ext_func_obj_p->u.built_in.routine_id = (uint8_t) id;
ext_func_obj_p->u.built_in.u2.routine_flags = ECMA_NATIVE_HANDLER_FLAGS_NONE;
#if JERRY_BUILTIN_REALMS
ECMA_SET_INTERNAL_VALUE_POINTER (ext_func_obj_p->u.built_in.realm_value, ecma_builtin_get_global ());
#endif /* JERRY_BUILTIN_REALMS */
return function_obj_p;
} /* ecma_op_create_native_handler */
#endif /* JERRY_ESNEXT */
/**
* Get compiled code of a function object.
*
* @return compiled code
*/
extern inline const ecma_compiled_code_t *JERRY_ATTR_ALWAYS_INLINE
ecma_op_function_get_compiled_code (ecma_extended_object_t *function_p) /**< function pointer */
{
#if JERRY_SNAPSHOT_EXEC
if (JERRY_LIKELY (function_p->u.function.bytecode_cp != ECMA_NULL_POINTER))
{
return ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t, function_p->u.function.bytecode_cp);
}
return ((ecma_static_function_t *) function_p)->bytecode_p;
#else /* !JERRY_SNAPSHOT_EXEC */
return ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t, function_p->u.function.bytecode_cp);
#endif /* JERRY_SNAPSHOT_EXEC */
} /* ecma_op_function_get_compiled_code */
#if JERRY_BUILTIN_REALMS
/**
* Get realm from a byte code.
*
* Note:
* Does not increase the reference counter.
*
* @return pointer to realm (global) object
*/
extern inline ecma_global_object_t *JERRY_ATTR_ALWAYS_INLINE
ecma_op_function_get_realm (const ecma_compiled_code_t *bytecode_header_p) /**< byte code header */
{
#if JERRY_SNAPSHOT_EXEC
if (JERRY_UNLIKELY (bytecode_header_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION))
{
return (ecma_global_object_t *) ecma_builtin_get_global ();
}
#endif /* JERRY_SNAPSHOT_EXEC */
ecma_value_t script_value = ((cbc_uint8_arguments_t *) bytecode_header_p)->script_value;
cbc_script_t *script_p = ECMA_GET_INTERNAL_VALUE_POINTER (cbc_script_t, script_value);
return (ecma_global_object_t *) script_p->realm_p;
} /* ecma_op_function_get_realm */
/**
* Get realm from a function
*
* Note:
* Does not increase the reference counter.
*
* @return realm (global) object
*/
ecma_global_object_t *
ecma_op_function_get_function_realm (ecma_object_t *func_obj_p) /**< function object */
{
while (true)
{
ecma_object_type_t type = ecma_get_object_type (func_obj_p);
if (type == ECMA_OBJECT_TYPE_FUNCTION)
{
ecma_extended_object_t *ext_function_obj_p = (ecma_extended_object_t *) func_obj_p;
const ecma_compiled_code_t *bytecode_data_p = ecma_op_function_get_compiled_code (ext_function_obj_p);
return ecma_op_function_get_realm (bytecode_data_p);
}
if (type == ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION)
{
ecma_extended_object_t *ext_function_obj_p = (ecma_extended_object_t *) func_obj_p;
return ECMA_GET_INTERNAL_VALUE_POINTER (ecma_global_object_t, ext_function_obj_p->u.built_in.realm_value);
}
if (type == ECMA_OBJECT_TYPE_NATIVE_FUNCTION)
{
ecma_native_function_t *native_function_p = (ecma_native_function_t *) func_obj_p;
return ECMA_GET_INTERNAL_VALUE_POINTER (ecma_global_object_t, native_function_p->realm_value);
}
#if JERRY_ESNEXT
if (type == ECMA_OBJECT_TYPE_CONSTRUCTOR_FUNCTION)
{
ecma_value_t script_value = ((ecma_extended_object_t *) func_obj_p)->u.constructor_function.script_value;
cbc_script_t *script_p = ECMA_GET_INTERNAL_VALUE_POINTER (cbc_script_t, script_value);
return (ecma_global_object_t *) script_p->realm_p;
}
#endif /* JERRY_ESNEXT */
#if JERRY_BUILTIN_PROXY
if (ECMA_OBJECT_IS_PROXY (func_obj_p))
{
ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) func_obj_p;
if (ecma_is_value_null (proxy_obj_p->handler))
{
ecma_raise_type_error (ECMA_ERR_PROTOTYPE_FROM_REVOKED_PROXY_IS_INVALID);
return NULL;
}
func_obj_p = ecma_get_object_from_value (proxy_obj_p->target);
continue;
}
#endif /* JERRY_BUILTIN_PROXY */
JERRY_ASSERT (type == ECMA_OBJECT_TYPE_BOUND_FUNCTION);
ecma_bound_function_t *bound_func_p = (ecma_bound_function_t *) func_obj_p;
func_obj_p =
ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t, bound_func_p->header.u.bound_function.target_function);
}
} /* ecma_op_function_get_function_realm */
#endif /* JERRY_BUILTIN_REALMS */
/**
* 15.3.5.3 implementation of [[HasInstance]] for Function objects
*
* @return true/false - if arguments are valid
* error - otherwise
* Returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_op_function_has_instance (ecma_object_t *func_obj_p, /**< Function object */
ecma_value_t value) /**< argument 'V' */
{
JERRY_ASSERT (func_obj_p != NULL && !ecma_is_lexical_environment (func_obj_p));
if (!ecma_is_value_object (value))
{
return ECMA_VALUE_FALSE;
}
while (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION)
{
JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION);
/* 1. 3. */
ecma_bound_function_t *bound_func_p = (ecma_bound_function_t *) func_obj_p;
func_obj_p =
ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t, bound_func_p->header.u.bound_function.target_function);
}
JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION
|| ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION
|| ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_CONSTRUCTOR_FUNCTION
|| ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_NATIVE_FUNCTION
|| ECMA_OBJECT_IS_PROXY (func_obj_p));
ecma_object_t *v_obj_p = ecma_get_object_from_value (value);
ecma_value_t prototype_obj_value = ecma_op_object_get_by_magic_id (func_obj_p, LIT_MAGIC_STRING_PROTOTYPE);
if (ECMA_IS_VALUE_ERROR (prototype_obj_value))
{
return prototype_obj_value;
}
if (!ecma_is_value_object (prototype_obj_value))
{
ecma_free_value (prototype_obj_value);
return ecma_raise_type_error (ECMA_ERR_OBJECT_EXPECTED);
}
ecma_object_t *prototype_obj_p = ecma_get_object_from_value (prototype_obj_value);
JERRY_ASSERT (prototype_obj_p != NULL);
#if JERRY_BUILTIN_PROXY
ecma_value_t result = ECMA_VALUE_ERROR;
#else /* !JERRY_BUILTIN_PROXY */
ecma_value_t result = ECMA_VALUE_FALSE;
#endif /* JERRY_BUILTIN_PROXY */
ecma_ref_object (v_obj_p);
while (true)
{
ecma_object_t *current_proto_p = ecma_op_object_get_prototype_of (v_obj_p);
ecma_deref_object (v_obj_p);
if (current_proto_p == NULL)
{
#if JERRY_BUILTIN_PROXY
result = ECMA_VALUE_FALSE;
#endif /* JERRY_BUILTIN_PROXY */
break;
}
else if (current_proto_p == ECMA_OBJECT_POINTER_ERROR)
{
break;
}
if (current_proto_p == prototype_obj_p)
{
ecma_deref_object (current_proto_p);
result = ECMA_VALUE_TRUE;
break;
}
/* Advance up on prototype chain. */
v_obj_p = current_proto_p;
}
ecma_deref_object (prototype_obj_p);
return result;
} /* ecma_op_function_has_instance */
#if JERRY_ESNEXT
/**
* GetSuperConstructor operation for class methods
*
* See also: ECMAScript v6, 12.3.5.2
*
* @return ECMA_VALUE_ERROR - if the operation fails
* super constructor - otherwise
*/
ecma_value_t
ecma_op_function_get_super_constructor (ecma_object_t *func_obj_p) /**< function object */
{
ecma_object_t *super_ctor_p = ecma_op_object_get_prototype_of (func_obj_p);
if (JERRY_UNLIKELY (super_ctor_p == ECMA_OBJECT_POINTER_ERROR))
{
return ECMA_VALUE_ERROR;
}
else if (super_ctor_p == NULL || !ecma_object_is_constructor (super_ctor_p))
{
if (super_ctor_p != NULL)
{
ecma_deref_object (super_ctor_p);
}
return ecma_raise_type_error (ECMA_ERR_SUPER_BINDING_MUST_BE_A_CONSTRUCTOR);
}
return ecma_make_object_value (super_ctor_p);
} /* ecma_op_function_get_super_constructor */
#endif /* JERRY_ESNEXT */
/**
* Ordinary internal method: GetPrototypeFromConstructor (constructor, intrinsicDefaultProto)
*
* See also:
* - ECMAScript v6, 9.1.15
* - ECMAScript v10, 9.1.14
*
* @return NULL - if the operation fail (exception on the global context is raised)
* pointer to the prototype object - otherwise
*/
ecma_object_t *
ecma_op_get_prototype_from_constructor (ecma_object_t *ctor_obj_p, /**< constructor to get prototype from */
ecma_builtin_id_t default_proto_id) /**< intrinsicDefaultProto */
{
JERRY_ASSERT (ecma_op_object_is_callable (ctor_obj_p));
JERRY_ASSERT (default_proto_id < ECMA_BUILTIN_ID__COUNT);
ecma_value_t proto = ecma_op_object_get_by_magic_id (ctor_obj_p, LIT_MAGIC_STRING_PROTOTYPE);
if (ECMA_IS_VALUE_ERROR (proto))
{
return NULL;
}
ecma_object_t *proto_obj_p;
if (!ecma_is_value_object (proto))
{
ecma_free_value (proto);
#if JERRY_BUILTIN_PROXY
if (ECMA_OBJECT_IS_PROXY (ctor_obj_p))
{
ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) ctor_obj_p;
if (ecma_is_value_null (proxy_obj_p->handler))
{
ecma_raise_type_error (ECMA_ERR_PROTOTYPE_FROM_REVOKED_PROXY_IS_INVALID);
return NULL;
}
}
#endif /* JERRY_BUILTIN_PROXY */
#if JERRY_BUILTIN_REALMS
proto_obj_p = ecma_builtin_get_from_realm (ecma_op_function_get_function_realm (ctor_obj_p), default_proto_id);
#else /* !JERRY_BUILTIN_REALMS */
proto_obj_p = ecma_builtin_get (default_proto_id);
#endif /* JERRY_BUILTIN_REALMS */
ecma_ref_object (proto_obj_p);
}
else
{
proto_obj_p = ecma_get_object_from_value (proto);
}
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_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_DERIVED_CTOR_RETURN_NOR_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.
*
* The input function object should be a pure JavaScript method
*
* @return the result of the function call.
*/
static ecma_value_t
ecma_op_function_call_simple (ecma_object_t *func_obj_p, /**< Function object */
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 */
{
JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION);
vm_frame_ctx_shared_args_t shared_args;
shared_args.header.status_flags = VM_FRAME_CTX_SHARED_HAS_ARG_LIST;
shared_args.header.function_object_p = func_obj_p;
shared_args.arg_list_p = arguments_list_p;
shared_args.arg_list_len = arguments_list_len;
/* Entering Function Code (ECMA-262 v5, 10.4.3) */
ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) func_obj_p;
ecma_object_t *scope_p = ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t, ext_func_p->u.function.scope_cp);
/* 8. */
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;
shared_args.header.bytecode_header_p = bytecode_data_p;
#if JERRY_BUILTIN_REALMS
ecma_global_object_t *realm_p = ecma_op_function_get_realm (bytecode_data_p);
#endif /* JERRY_BUILTIN_REALMS */
/* 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);
}
/* 1. */
switch (CBC_FUNCTION_GET_TYPE (status_flags))
{
#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 */
if (status_flags & CBC_CODE_FLAGS_STRICT_MODE)
{
break;
}
if (ecma_is_value_undefined (this_binding) || ecma_is_value_null (this_binding))
{
/* 2. */
#if JERRY_BUILTIN_REALMS
this_binding = realm_p->this_binding;
#else /* !JERRY_BUILTIN_REALMS */
this_binding = ecma_make_object_value (ecma_builtin_get_global ());
#endif /* JERRY_BUILTIN_REALMS */
}
else if (!ecma_is_value_object (this_binding))
{
/* 3., 4. */
this_binding = ecma_op_to_object (this_binding);
shared_args.header.status_flags |= VM_FRAME_CTX_SHARED_FREE_THIS;
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (this_binding));
}
break;
}
}
#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 */
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_UNLIKELY (shared_args.header.status_flags & VM_FRAME_CTX_SHARED_FREE_LOCAL_ENV))
{
ecma_deref_object (scope_p);
}
if (JERRY_UNLIKELY (shared_args.header.status_flags & VM_FRAME_CTX_SHARED_FREE_THIS))
{
ecma_free_value (this_binding);
}
return ret_value;
} /* ecma_op_function_call_simple */
/**
* Perform a built-in method call.
*
* @return the result of the function call.
*/
static ecma_value_t JERRY_ATTR_NOINLINE
ecma_op_function_call_native_built_in (ecma_object_t *func_obj_p, /**< Function object */
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 */
{
JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION);
#if JERRY_BUILTIN_REALMS
ecma_global_object_t *saved_global_object_p = JERRY_CONTEXT (global_object_p);
ecma_extended_object_t *ext_func_obj_p = (ecma_extended_object_t *) func_obj_p;
JERRY_CONTEXT (global_object_p) =
ECMA_GET_INTERNAL_VALUE_POINTER (ecma_global_object_t, ext_func_obj_p->u.built_in.realm_value);
#endif /* JERRY_BUILTIN_REALMS */
ecma_value_t ret_value =
ecma_builtin_dispatch_call (func_obj_p, this_arg_value, arguments_list_p, arguments_list_len);
#if JERRY_BUILTIN_REALMS
JERRY_CONTEXT (global_object_p) = saved_global_object_p;
#endif /* JERRY_BUILTIN_REALMS */
return ret_value;
} /* ecma_op_function_call_native_built_in */
/**
* Perform a native C method call which was registered via the API.
*
* @return the result of the function call.
*/
static ecma_value_t JERRY_ATTR_NOINLINE
ecma_op_function_call_native (ecma_object_t *func_obj_p, /**< Function object */
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 */
{
JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_NATIVE_FUNCTION);
ecma_native_function_t *native_function_p = (ecma_native_function_t *) func_obj_p;
#if JERRY_BUILTIN_REALMS
ecma_global_object_t *saved_global_object_p = JERRY_CONTEXT (global_object_p);
JERRY_CONTEXT (global_object_p) =
ECMA_GET_INTERNAL_VALUE_POINTER (ecma_global_object_t, native_function_p->realm_value);
#endif /* JERRY_BUILTIN_REALMS */
jerry_call_info_t call_info;
call_info.function = ecma_make_object_value (func_obj_p);
call_info.this_value = this_arg_value;
#if JERRY_ESNEXT
ecma_object_t *new_target_p = JERRY_CONTEXT (current_new_target_p);
call_info.new_target = (new_target_p == NULL) ? ECMA_VALUE_UNDEFINED : ecma_make_object_value (new_target_p);
#else /* JERRY_ESNEXT */
call_info.new_target = ECMA_VALUE_UNDEFINED;
#endif /* JERRY_ESNEXT */
JERRY_ASSERT (native_function_p->native_handler_cb != NULL);
ecma_value_t ret_value = native_function_p->native_handler_cb (&call_info, arguments_list_p, arguments_list_len);
#if JERRY_BUILTIN_REALMS
JERRY_CONTEXT (global_object_p) = saved_global_object_p;
#endif /* JERRY_BUILTIN_REALMS */
if (JERRY_UNLIKELY (ecma_is_value_exception (ret_value)))
{
ecma_throw_exception (ret_value);
return ECMA_VALUE_ERROR;
}
#if JERRY_DEBUGGER
JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_EXCEPTION_THROWN);
#endif /* JERRY_DEBUGGER */
return ret_value;
} /* ecma_op_function_call_native */
/**
* Append the bound arguments into the given collection
*
* Note:
* - The whole bound chain is resolved
* - The first element of the collection contains the bounded this value
*
* @return target function of the bound function
*/
JERRY_ATTR_NOINLINE static ecma_object_t *
ecma_op_bound_function_get_argument_list (ecma_object_t *func_obj_p, /**< bound bunction object */
ecma_collection_t *list_p) /**< list of arguments */
{
JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION);
ecma_bound_function_t *bound_func_p = (ecma_bound_function_t *) func_obj_p;
func_obj_p =
ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t, bound_func_p->header.u.bound_function.target_function);
ecma_value_t args_len_or_this = bound_func_p->header.u.bound_function.args_len_or_this;
uint32_t args_length = 1;
if (ecma_is_value_integer_number (args_len_or_this))
{
args_length = (uint32_t) ecma_get_integer_from_value (args_len_or_this);
}
/* 5. */
if (args_length != 1)
{
const ecma_value_t *args_p = (const ecma_value_t *) (bound_func_p + 1);
list_p->buffer_p[0] = *args_p;
if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION)
{
func_obj_p = ecma_op_bound_function_get_argument_list (func_obj_p, list_p);
}
ecma_collection_append (list_p, args_p + 1, args_length - 1);
}
else
{
list_p->buffer_p[0] = args_len_or_this;
}
return func_obj_p;
} /* ecma_op_bound_function_get_argument_list */
/**
* [[Call]] internal method for bound function objects
*
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
static ecma_value_t JERRY_ATTR_NOINLINE
ecma_op_function_call_bound (ecma_object_t *func_obj_p, /**< Function object */
const ecma_value_t *arguments_list_p, /**< arguments list */
uint32_t arguments_list_len) /**< length of arguments list */
{
JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION);
JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_DIRECT_EVAL;
ecma_collection_t *bound_arg_list_p = ecma_new_collection ();
ecma_collection_push_back (bound_arg_list_p, ECMA_VALUE_EMPTY);
ecma_object_t *target_obj_p = ecma_op_bound_function_get_argument_list (func_obj_p, bound_arg_list_p);
ecma_collection_append (bound_arg_list_p, arguments_list_p, arguments_list_len);
JERRY_ASSERT (!ecma_is_value_empty (bound_arg_list_p->buffer_p[0]));
ecma_value_t ret_value = ecma_op_function_call (target_obj_p,
bound_arg_list_p->buffer_p[0],
bound_arg_list_p->buffer_p + 1,
(uint32_t) (bound_arg_list_p->item_count - 1));
ecma_collection_destroy (bound_arg_list_p);
return ret_value;
} /* ecma_op_function_call_bound */
/**
* 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_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
*/
ecma_value_t
ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */
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 */
{
JERRY_ASSERT (func_obj_p != NULL && !ecma_is_lexical_environment (func_obj_p));
ECMA_CHECK_STACK_USAGE ();
#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;
}
#endif /* JERRY_ESNEXT */
ecma_value_t result;
switch (ecma_get_object_type (func_obj_p))
{
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
case ECMA_OBJECT_TYPE_CONSTRUCTOR_FUNCTION:
{
result = ecma_raise_type_error (ECMA_ERR_CLASS_CONSTRUCTOR_NEW);
break;
}
#endif /* JERRY_ESNEXT */
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_EXPECTED_A_FUNCTION);
break;
}
}
#if JERRY_ESNEXT
JERRY_CONTEXT (current_new_target_p) = old_new_target_p;
#endif /* JERRY_ESNEXT */
return result;
} /* ecma_op_function_call */
/**
* [[Construct]] internal method for ECMAScript function objects
*
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
static ecma_value_t
ecma_op_function_construct_simple (ecma_object_t *func_obj_p, /**< Function object */
ecma_object_t *new_target_p, /**< new target */
const ecma_value_t *arguments_list_p, /**< arguments list */
uint32_t arguments_list_len) /**< length of arguments list */
{
JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION);
ecma_object_t *new_this_obj_p = NULL;
ecma_value_t this_arg;
#if JERRY_ESNEXT
ecma_extended_object_t *ext_func_obj_p = (ecma_extended_object_t *) func_obj_p;
/* 5. */
if (!ECMA_GET_THIRD_BIT_FROM_POINTER_TAG (ext_func_obj_p->u.function.scope_cp))
{
#endif /* JERRY_ESNEXT */
/* 5.a */
ecma_object_t *proto_p = ecma_op_get_prototype_from_constructor (new_target_p, ECMA_BUILTIN_ID_OBJECT_PROTOTYPE);
/* 5.b */
if (JERRY_UNLIKELY (proto_p == NULL))
{
return ECMA_VALUE_ERROR;
}
new_this_obj_p = ecma_create_object (proto_p, 0, ECMA_OBJECT_TYPE_GENERAL);
ecma_deref_object (proto_p);
this_arg = ecma_make_object_value (new_this_obj_p);
#if JERRY_ESNEXT
}
else
{
this_arg = ECMA_VALUE_UNDEFINED;
}
/* 6. */
ecma_object_t *old_new_target_p = JERRY_CONTEXT (current_new_target_p);
JERRY_CONTEXT (current_new_target_p) = new_target_p;
#endif /* JERRY_ESNEXT */
ecma_value_t ret_value = ecma_op_function_call_simple (func_obj_p, this_arg, arguments_list_p, arguments_list_len);
#if JERRY_ESNEXT
JERRY_CONTEXT (current_new_target_p) = old_new_target_p;
#endif /* JERRY_ESNEXT */
/* 13.a */
if (ECMA_IS_VALUE_ERROR (ret_value) || ecma_is_value_object (ret_value))
{
#if JERRY_ESNEXT
if (new_this_obj_p != NULL)
{
ecma_deref_object (new_this_obj_p);
}
#else /* !JERRY_ESNEXT */
ecma_deref_object (new_this_obj_p);
#endif /* JERRY_ESNEXT */
return ret_value;
}
/* 13.b */
ecma_free_value (ret_value);
return this_arg;
} /* ecma_op_function_construct_simple */
/**
* [[Construct]] internal method for built-in function objects
*
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
static ecma_value_t
ecma_op_function_construct_built_in (ecma_object_t *func_obj_p, /**< Function object */
ecma_object_t *new_target_p, /**< new target */
const ecma_value_t *arguments_list_p, /**< arguments list */
uint32_t arguments_list_len) /**< length of arguments list */
{
JERRY_UNUSED (new_target_p);
JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION);
#if JERRY_BUILTIN_REALMS
ecma_global_object_t *saved_global_object_p = JERRY_CONTEXT (global_object_p);
ecma_value_t realm_value = ((ecma_extended_object_t *) func_obj_p)->u.built_in.realm_value;
JERRY_CONTEXT (global_object_p) = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_global_object_t, realm_value);
#endif /* JERRY_BUILTIN_REALMS */
#if JERRY_ESNEXT
ecma_object_t *old_new_target = JERRY_CONTEXT (current_new_target_p);
JERRY_CONTEXT (current_new_target_p) = new_target_p;
#endif /* JERRY_ESNEXT */
ecma_value_t ret_value = ecma_builtin_dispatch_construct (func_obj_p, arguments_list_p, arguments_list_len);
#if JERRY_ESNEXT
JERRY_CONTEXT (current_new_target_p) = old_new_target;
#endif /* JERRY_ESNEXT */
#if JERRY_BUILTIN_REALMS
JERRY_CONTEXT (global_object_p) = saved_global_object_p;
#endif /* JERRY_BUILTIN_REALMS */
return ret_value;
} /* ecma_op_function_construct_built_in */
/**
* [[Construct]] internal method for bound function objects
*
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
static ecma_value_t JERRY_ATTR_NOINLINE
ecma_op_function_construct_bound (ecma_object_t *func_obj_p, /**< Function object */
ecma_object_t *new_target_p, /**< new target */
const ecma_value_t *arguments_list_p, /**< arguments list */
uint32_t arguments_list_len) /**< length of arguments list */
{
JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION);
ecma_collection_t *bound_arg_list_p = ecma_new_collection ();
ecma_collection_push_back (bound_arg_list_p, ECMA_VALUE_EMPTY);
ecma_object_t *target_obj_p = ecma_op_bound_function_get_argument_list (func_obj_p, bound_arg_list_p);
ecma_collection_append (bound_arg_list_p, arguments_list_p, arguments_list_len);
if (func_obj_p == new_target_p)
{
new_target_p = target_obj_p;
}
ecma_value_t ret_value = ecma_op_function_construct (target_obj_p,
new_target_p,
bound_arg_list_p->buffer_p + 1,
(uint32_t) (bound_arg_list_p->item_count - 1));
ecma_collection_destroy (bound_arg_list_p);
return ret_value;
} /* ecma_op_function_construct_bound */
#if JERRY_ESNEXT
/**
* [[Construct]] internal method for class implicit constructor objects
*
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
static ecma_value_t
ecma_op_function_construct_constructor (ecma_object_t *func_obj_p, /**< Function object */
ecma_object_t *new_target_p, /**< new target */
const ecma_value_t *arguments_list_p, /**< arguments list */
uint32_t arguments_list_len) /**< length of arguments list */
{
JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_CONSTRUCTOR_FUNCTION);
ecma_extended_object_t *constructor_object_p = (ecma_extended_object_t *) func_obj_p;
if (!(constructor_object_p->u.constructor_function.flags & ECMA_CONSTRUCTOR_FUNCTION_HAS_HERITAGE))
{
ecma_object_t *proto_p = ecma_op_get_prototype_from_constructor (new_target_p, ECMA_BUILTIN_ID_OBJECT_PROTOTYPE);
if (JERRY_UNLIKELY (proto_p == NULL))
{
return ECMA_VALUE_ERROR;
}
ecma_object_t *new_this_object_p = ecma_create_object (proto_p, 0, ECMA_OBJECT_TYPE_GENERAL);
ecma_deref_object (proto_p);
jerry_value_t new_this_value = ecma_make_object_value (new_this_object_p);
jerry_value_t ret_value = opfunc_init_class_fields (func_obj_p, new_this_value);
if (ECMA_IS_VALUE_ERROR (ret_value))
{
ecma_deref_object (new_this_object_p);
return ret_value;
}
return new_this_value;
}
ecma_value_t super_ctor = ecma_op_function_get_super_constructor (func_obj_p);
if (ECMA_IS_VALUE_ERROR (super_ctor))
{
return super_ctor;
}
ecma_object_t *super_ctor_p = ecma_get_object_from_value (super_ctor);
ecma_value_t result = ecma_op_function_construct (super_ctor_p, new_target_p, arguments_list_p, arguments_list_len);
ecma_deref_object (super_ctor_p);
if (ecma_is_value_object (result))
{
ecma_value_t fields_value = opfunc_init_class_fields (func_obj_p, result);
if (ECMA_IS_VALUE_ERROR (fields_value))
{
ecma_free_value (result);
return fields_value;
}
}
return result;
} /* ecma_op_function_construct_constructor */
#endif /* JERRY_ESNEXT */
/**
* [[Construct]] internal method for external function objects
*
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
static ecma_value_t
ecma_op_function_construct_native (ecma_object_t *func_obj_p, /**< Function object */
ecma_object_t *new_target_p, /**< new target */
const ecma_value_t *arguments_list_p, /**< arguments list */
uint32_t arguments_list_len) /**< length of arguments list */
{
JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_NATIVE_FUNCTION);
ecma_object_t *proto_p = ecma_op_get_prototype_from_constructor (new_target_p, ECMA_BUILTIN_ID_OBJECT_PROTOTYPE);
if (JERRY_UNLIKELY (proto_p == NULL))
{
return ECMA_VALUE_ERROR;
}
ecma_object_t *new_this_obj_p = ecma_create_object (proto_p, 0, ECMA_OBJECT_TYPE_GENERAL);
ecma_value_t this_arg = ecma_make_object_value (new_this_obj_p);
ecma_deref_object (proto_p);
#if JERRY_ESNEXT
ecma_object_t *old_new_target_p = JERRY_CONTEXT (current_new_target_p);
JERRY_CONTEXT (current_new_target_p) = new_target_p;
#endif /* JERRY_ESNEXT */
ecma_value_t ret_value = ecma_op_function_call_native (func_obj_p, this_arg, arguments_list_p, arguments_list_len);
#if JERRY_ESNEXT
JERRY_CONTEXT (current_new_target_p) = old_new_target_p;
#endif /* JERRY_ESNEXT */
if (ECMA_IS_VALUE_ERROR (ret_value) || ecma_is_value_object (ret_value))
{
ecma_deref_object (new_this_obj_p);
return ret_value;
}
ecma_free_value (ret_value);
return this_arg;
} /* ecma_op_function_construct_native */
/**
* General [[Construct]] implementation function objects
*
* See also: ECMAScript v6, 9.2.2
*
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */
ecma_object_t *new_target_p, /**< new target */
const ecma_value_t *arguments_list_p, /**< arguments list */
uint32_t arguments_list_len) /**< length of arguments list */
{
JERRY_ASSERT (func_obj_p != NULL && !ecma_is_lexical_environment (func_obj_p));
switch (ecma_get_object_type (func_obj_p))
{
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
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_ESNEXT
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 ();
}
}
return ECMA_VALUE_UNDEFINED;
} /* ecma_op_function_construct */
/**
* Lazy instantiation of 'prototype' property for non-builtin and external functions
*
* @return pointer to newly instantiated property
*/
static ecma_property_t *
ecma_op_lazy_instantiate_prototype_object (ecma_object_t *object_p) /**< the function object */
{
JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_FUNCTION
|| ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_NATIVE_FUNCTION);
#if JERRY_BUILTIN_REALMS
ecma_global_object_t *global_object_p;
if (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_FUNCTION)
{
const ecma_compiled_code_t *bytecode_data_p;
bytecode_data_p = ecma_op_function_get_compiled_code ((ecma_extended_object_t *) object_p);
global_object_p = ecma_op_function_get_realm (bytecode_data_p);
}
else
{
ecma_native_function_t *native_function_p = (ecma_native_function_t *) object_p;
global_object_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_global_object_t, native_function_p->realm_value);
}
#endif /* JERRY_BUILTIN_REALMS */
/* ECMA-262 v5, 13.2, 16-18 */
ecma_object_t *proto_object_p = NULL;
bool init_constructor = true;
#if JERRY_ESNEXT
if (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_FUNCTION)
{
const ecma_compiled_code_t *byte_code_p = ecma_op_function_get_compiled_code ((ecma_extended_object_t *) object_p);
if (!CBC_FUNCTION_HAS_PROTOTYPE (byte_code_p->status_flags))
{
return NULL;
}
if (CBC_FUNCTION_GET_TYPE (byte_code_p->status_flags) == CBC_FUNCTION_GENERATOR)
{
ecma_object_t *prototype_p;
#if JERRY_BUILTIN_REALMS
prototype_p = ecma_builtin_get_from_realm (global_object_p, ECMA_BUILTIN_ID_GENERATOR_PROTOTYPE);
#else /* !JERRY_BUILTIN_REALMS */
prototype_p = ecma_builtin_get (ECMA_BUILTIN_ID_GENERATOR_PROTOTYPE);
#endif /* JERRY_BUILTIN_REALMS */
proto_object_p = ecma_create_object (prototype_p, 0, ECMA_OBJECT_TYPE_GENERAL);
init_constructor = false;
}
if (CBC_FUNCTION_GET_TYPE (byte_code_p->status_flags) == CBC_FUNCTION_ASYNC_GENERATOR)
{
ecma_object_t *prototype_p;
#if JERRY_BUILTIN_REALMS
prototype_p = ecma_builtin_get_from_realm (global_object_p, ECMA_BUILTIN_ID_ASYNC_GENERATOR_PROTOTYPE);
#else /* !JERRY_BUILTIN_REALMS */
prototype_p = ecma_builtin_get (ECMA_BUILTIN_ID_ASYNC_GENERATOR_PROTOTYPE);
#endif /* JERRY_BUILTIN_REALMS */
proto_object_p = ecma_create_object (prototype_p, 0, ECMA_OBJECT_TYPE_GENERAL);
init_constructor = false;
}
}
#endif /* JERRY_ESNEXT */
#if JERRY_ESNEXT
if (proto_object_p == NULL)
#endif /* JERRY_ESNEXT */
{
ecma_object_t *prototype_p;
#if JERRY_BUILTIN_REALMS
prototype_p = ecma_builtin_get_from_realm (global_object_p, ECMA_BUILTIN_ID_OBJECT_PROTOTYPE);
#else /* !JERRY_BUILTIN_REALMS */
prototype_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE);
#endif /* JERRY_BUILTIN_REALMS */
proto_object_p = ecma_op_create_object_object_noarg_and_set_prototype (prototype_p);
}
/* 17. */
if (init_constructor)
{
ecma_property_value_t *constructor_prop_value_p;
constructor_prop_value_p = ecma_create_named_data_property (proto_object_p,
ecma_get_magic_string (LIT_MAGIC_STRING_CONSTRUCTOR),
ECMA_PROPERTY_CONFIGURABLE_WRITABLE,
NULL);
constructor_prop_value_p->value = ecma_make_object_value (object_p);
}
/* 18. */
ecma_property_t *prototype_prop_p;
ecma_property_value_t *prototype_prop_value_p;
prototype_prop_value_p = ecma_create_named_data_property (object_p,
ecma_get_magic_string (LIT_MAGIC_STRING_PROTOTYPE),
ECMA_PROPERTY_BUILT_IN_WRITABLE,
&prototype_prop_p);
prototype_prop_value_p->value = ecma_make_object_value (proto_object_p);
ecma_deref_object (proto_object_p);
return prototype_prop_p;
} /* ecma_op_lazy_instantiate_prototype_object */
/**
* Lazy instantiation of non-builtin ecma function object's properties
*
* Warning:
* Only non-configurable properties could be instantiated lazily in this function,
* as configurable properties could be deleted and it would be incorrect
* to reinstantiate them in the function in second time.
*
* @return pointer to newly instantiated property, if a property was instantiated,
* NULL - otherwise
*/
ecma_property_t *
ecma_op_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, /**< the function object */
ecma_string_t *property_name_p) /**< property name */
{
JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_FUNCTION);
#if JERRY_ESNEXT
if (ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_LENGTH))
{
ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p;
if (ECMA_GET_FIRST_BIT_FROM_POINTER_TAG (ext_func_p->u.function.scope_cp))
{
return NULL;
}
/* Initialize 'length' property */
const ecma_compiled_code_t *bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p);
uint32_t len;
if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
{
cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_data_p;
len = args_p->argument_end;
}
else
{
cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) bytecode_data_p;
len = args_p->argument_end;
}
if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_HAS_EXTENDED_INFO)
{
uint8_t *extended_info_p = ecma_compiled_code_resolve_extended_info (bytecode_data_p);
if (*extended_info_p & CBC_EXTENDED_CODE_FLAGS_HAS_ARGUMENT_LENGTH)
{
len = ecma_extended_info_decode_vlq (&extended_info_p);
}
}
ecma_property_t *value_prop_p;
ecma_property_value_t *value_p =
ecma_create_named_data_property (object_p, property_name_p, ECMA_PROPERTY_BUILT_IN_CONFIGURABLE, &value_prop_p);
value_p->value = ecma_make_uint32_value (len);
return value_prop_p;
}
if (ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_NAME))
{
ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p;
if (ECMA_GET_SECOND_BIT_FROM_POINTER_TAG (ext_func_p->u.function.scope_cp))
{
return NULL;
}
const ecma_compiled_code_t *bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p);
if (CBC_FUNCTION_GET_TYPE (bytecode_data_p->status_flags) == CBC_FUNCTION_CONSTRUCTOR)
{
return NULL;
}
ecma_value_t value = *ecma_compiled_code_resolve_function_name (bytecode_data_p);
JERRY_ASSERT (ecma_is_value_string (value));
/* Initialize 'name' property */
ecma_property_t *value_prop_p;
ecma_property_value_t *value_p =
ecma_create_named_data_property (object_p, property_name_p, ECMA_PROPERTY_BUILT_IN_CONFIGURABLE, &value_prop_p);
value_p->value = ecma_copy_value (value);
return value_prop_p;
}
#endif /* JERRY_ESNEXT */
if (ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_PROTOTYPE)
&& ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_FUNCTION)
{
return ecma_op_lazy_instantiate_prototype_object (object_p);
}
const bool is_arguments = ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_ARGUMENTS);
if (is_arguments || ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_CALLER))
{
const ecma_compiled_code_t *bytecode_data_p;
bytecode_data_p = ecma_op_function_get_compiled_code ((ecma_extended_object_t *) object_p);
#if JERRY_ESNEXT
if (!(bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE)
&& CBC_FUNCTION_GET_TYPE (bytecode_data_p->status_flags) == CBC_FUNCTION_NORMAL)
{
ecma_property_t *value_prop_p;
/* The property_name_p argument contains the name. */
ecma_property_value_t *value_p =
ecma_create_named_data_property (object_p, property_name_p, ECMA_PROPERTY_BUILT_IN_FIXED, &value_prop_p);
value_p->value = is_arguments ? ECMA_VALUE_NULL : ECMA_VALUE_UNDEFINED;
return value_prop_p;
}
#else /* !JERRY_ESNEXT */
if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE)
{
ecma_object_t *thrower_p = ecma_builtin_get (ECMA_BUILTIN_ID_TYPE_ERROR_THROWER);
ecma_property_t *caller_prop_p;
/* The property_name_p argument contains the name. */
ecma_create_named_accessor_property (object_p,
property_name_p,
thrower_p,
thrower_p,
ECMA_PROPERTY_BUILT_IN_FIXED,
&caller_prop_p);
return caller_prop_p;
}
#endif /* JERRY_ESNEXT */
}
return NULL;
} /* ecma_op_function_try_to_lazy_instantiate_property */
/**
* Create specification defined non-configurable properties for external functions.
*
* See also:
* ECMA-262 v5, 15.3.4.5
*
* @return pointer property, if one was instantiated,
* NULL - otherwise.
*/
ecma_property_t *
ecma_op_external_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, /**< object */
ecma_string_t *property_name_p) /**< property's name */
{
JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_NATIVE_FUNCTION);
if (ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_PROTOTYPE))
{
return ecma_op_lazy_instantiate_prototype_object (object_p);
}
return NULL;
} /* ecma_op_external_function_try_to_lazy_instantiate_property */
/**
* Create specification defined non-configurable properties for bound functions.
*
* See also:
* ECMA-262 v5, 15.3.4.5
*
* @return pointer property, if one was instantiated,
* NULL - otherwise.
*/
ecma_property_t *
ecma_op_bound_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, /**< object */
ecma_string_t *property_name_p) /**< property's name */
{
JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION);
if (ecma_string_is_length (property_name_p))
{
ecma_bound_function_t *bound_func_p = (ecma_bound_function_t *) object_p;
ecma_value_t args_len_or_this = bound_func_p->header.u.bound_function.args_len_or_this;
ecma_number_t length = 0;
ecma_integer_value_t args_length = 1;
uint8_t length_attributes;
if (ecma_is_value_integer_number (args_len_or_this))
{
args_length = ecma_get_integer_from_value (args_len_or_this);
}
#if JERRY_ESNEXT
if (ECMA_GET_FIRST_BIT_FROM_POINTER_TAG (bound_func_p->header.u.bound_function.target_function))
{
return NULL;
}
length_attributes = ECMA_PROPERTY_BUILT_IN_CONFIGURABLE;
length = ecma_get_number_from_value (bound_func_p->target_length) - (args_length - 1);
#else /* !JERRY_ESNEXT */
length_attributes = ECMA_PROPERTY_BUILT_IN_FIXED;
ecma_object_t *target_func_p;
target_func_p =
ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t, bound_func_p->header.u.bound_function.target_function);
if (ecma_object_get_class_name (target_func_p) == LIT_MAGIC_STRING_FUNCTION_UL)
{
/* The property_name_p argument contains the 'length' string. */
ecma_value_t get_len_value = ecma_op_object_get (target_func_p, property_name_p);
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (get_len_value));
JERRY_ASSERT (ecma_is_value_integer_number (get_len_value));
length = (ecma_number_t) (ecma_get_integer_from_value (get_len_value) - (args_length - 1));
}
#endif /* JERRY_ESNEXT */
if (length < 0)
{
length = 0;
}
ecma_property_t *len_prop_p;
ecma_property_value_t *len_prop_value_p =
ecma_create_named_data_property (object_p, property_name_p, length_attributes, &len_prop_p);
len_prop_value_p->value = ecma_make_number_value (length);
return len_prop_p;
}
#if !JERRY_ESNEXT
if (ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_CALLER)
|| ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_ARGUMENTS))
{
ecma_object_t *thrower_p = ecma_builtin_get (ECMA_BUILTIN_ID_TYPE_ERROR_THROWER);
ecma_property_t *caller_prop_p;
/* The string_p argument contans the name. */
ecma_create_named_accessor_property (object_p,
property_name_p,
thrower_p,
thrower_p,
ECMA_PROPERTY_BUILT_IN_FIXED,
&caller_prop_p);
return caller_prop_p;
}
#endif /* !JERRY_ESNEXT */
return NULL;
} /* ecma_op_bound_function_try_to_lazy_instantiate_property */
#if JERRY_ESNEXT
/**
* Delete configurable properties of functions.
*/
void
ecma_op_function_delete_built_in_property (ecma_object_t *object_p, /**< object */
ecma_string_t *property_name_p) /**< property name */
{
ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p;
if (ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_LENGTH))
{
JERRY_ASSERT (!ECMA_GET_FIRST_BIT_FROM_POINTER_TAG (ext_func_p->u.function.scope_cp));
ECMA_SET_FIRST_BIT_TO_POINTER_TAG (ext_func_p->u.function.scope_cp);
return;
}
JERRY_ASSERT (ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_NAME));
JERRY_ASSERT (!ECMA_GET_SECOND_BIT_FROM_POINTER_TAG (ext_func_p->u.function.scope_cp));
ECMA_SET_SECOND_BIT_TO_POINTER_TAG (ext_func_p->u.function.scope_cp);
} /* ecma_op_function_delete_built_in_property */
/**
* Delete configurable properties of bound functions.
*/
void
ecma_op_bound_function_delete_built_in_property (ecma_object_t *object_p, /**< object */
ecma_string_t *property_name_p) /**< property name */
{
JERRY_UNUSED (property_name_p);
ecma_bound_function_t *bound_func_p = (ecma_bound_function_t *) object_p;
JERRY_ASSERT (ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_LENGTH));
JERRY_ASSERT (!ECMA_GET_FIRST_BIT_FROM_POINTER_TAG (bound_func_p->header.u.bound_function.target_function));
ECMA_SET_FIRST_BIT_TO_POINTER_TAG (bound_func_p->header.u.bound_function.target_function);
} /* ecma_op_bound_function_delete_built_in_property */
#endif /* JERRY_ESNEXT */
/**
* List names of a Function object's lazy instantiated properties,
* adding them to corresponding string collections
*
* See also:
* ecma_op_function_try_to_lazy_instantiate_property
*/
void
ecma_op_function_list_lazy_property_names (ecma_object_t *object_p, /**< functionobject */
ecma_collection_t *prop_names_p, /**< prop name collection */
ecma_property_counter_t *prop_counter_p, /**< property counters */
jerry_property_filter_t filter) /**< property name filter options */
{
if (filter & JERRY_PROPERTY_FILTER_EXCLUDE_STRINGS)
{
return;
}
const ecma_compiled_code_t *bytecode_data_p;
bytecode_data_p = ecma_op_function_get_compiled_code ((ecma_extended_object_t *) object_p);
#if JERRY_ESNEXT
ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p;
if (!ECMA_GET_FIRST_BIT_FROM_POINTER_TAG (ext_func_p->u.function.scope_cp))
{
/* Unintialized 'length' property is non-enumerable (ECMA-262 v6, 19.2.4.1) */
ecma_collection_push_back (prop_names_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_LENGTH));
prop_counter_p->string_named_props++;
}
if (CBC_FUNCTION_GET_TYPE (bytecode_data_p->status_flags) != CBC_FUNCTION_CONSTRUCTOR
&& !ECMA_GET_SECOND_BIT_FROM_POINTER_TAG (ext_func_p->u.function.scope_cp))
{
/* Unintialized 'name' property is non-enumerable (ECMA-262 v6, 19.2.4.2) */
ecma_collection_push_back (prop_names_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_NAME));
prop_counter_p->string_named_props++;
}
#else /* !JERRY_ESNEXT */
/* 'length' property is non-enumerable (ECMA-262 v5, 13.2.5) */
ecma_collection_push_back (prop_names_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_LENGTH));
prop_counter_p->string_named_props++;
#endif /* JERRY_ESNEXT */
#if JERRY_ESNEXT
if (!CBC_FUNCTION_HAS_PROTOTYPE (bytecode_data_p->status_flags)
|| (CBC_FUNCTION_GET_TYPE (bytecode_data_p->status_flags) == CBC_FUNCTION_CONSTRUCTOR))
{
return;
}
bool append_caller_and_arguments = !(bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE);
#else /* !JERRY_ESNEXT */
bool append_caller_and_arguments = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE);
#endif /* JERRY_ESNEXT */
if (append_caller_and_arguments)
{
/* 'arguments' property is non-enumerable (ECMA-262 v5, 13.2.5) */
ecma_collection_push_back (prop_names_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_ARGUMENTS));
/* 'caller' property is non-enumerable (ECMA-262 v5, 13.2.5) */
ecma_collection_push_back (prop_names_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_CALLER));
prop_counter_p->string_named_props += 2;
}
/* 'prototype' property is non-enumerable (ECMA-262 v5, 13.2.18) */
ecma_collection_push_back (prop_names_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_PROTOTYPE));
prop_counter_p->string_named_props++;
} /* ecma_op_function_list_lazy_property_names */
/**
* List names of an External Function object's lazy instantiated properties,
* adding them to corresponding string collections
*
* See also:
* ecma_op_external_function_try_to_lazy_instantiate_property
*/
void
ecma_op_external_function_list_lazy_property_names (ecma_object_t *object_p, /**< function object */
ecma_collection_t *prop_names_p, /**< prop name collection */
ecma_property_counter_t *prop_counter_p, /**< property counters */
jerry_property_filter_t filter) /**< property name
* filter options */
{
JERRY_UNUSED (object_p);
if (filter & JERRY_PROPERTY_FILTER_EXCLUDE_STRINGS)
{
return;
}
/* 'prototype' property is non-enumerable (ECMA-262 v5, 13.2.18) */
ecma_collection_push_back (prop_names_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_PROTOTYPE));
prop_counter_p->string_named_props++;
} /* ecma_op_external_function_list_lazy_property_names */
/**
* List names of a Bound Function object's lazy instantiated properties,
* adding them to corresponding string collections
*
* See also:
* ecma_op_bound_function_try_to_lazy_instantiate_property
*/
void
ecma_op_bound_function_list_lazy_property_names (ecma_object_t *object_p, /**< bound function object*/
ecma_collection_t *prop_names_p, /**< prop name collection */
ecma_property_counter_t *prop_counter_p, /**< property counters */
jerry_property_filter_t filter) /**< property name filter options */
{
if (filter & JERRY_PROPERTY_FILTER_EXCLUDE_STRINGS)
{
return;
}
#if JERRY_ESNEXT
/* Unintialized 'length' property is non-enumerable (ECMA-262 v6, 19.2.4.1) */
ecma_bound_function_t *bound_func_p = (ecma_bound_function_t *) object_p;
if (!ECMA_GET_FIRST_BIT_FROM_POINTER_TAG (bound_func_p->header.u.bound_function.target_function))
{
ecma_collection_push_back (prop_names_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_LENGTH));
prop_counter_p->string_named_props++;
}
#else /* !JERRY_ESNEXT */
JERRY_UNUSED (object_p);
/* 'length' property is non-enumerable (ECMA-262 v5, 13.2.5) */
ecma_collection_push_back (prop_names_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_LENGTH));
prop_counter_p->string_named_props++;
#endif /* JERRY_ESNEXT */
/* 'caller' property is non-enumerable (ECMA-262 v5, 13.2.5) */
ecma_collection_push_back (prop_names_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_CALLER));
/* 'arguments' property is non-enumerable (ECMA-262 v5, 13.2.5) */
ecma_collection_push_back (prop_names_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_ARGUMENTS));
prop_counter_p->string_named_props += 2;
} /* ecma_op_bound_function_list_lazy_property_names */
/**
* @}
* @}
*/