Máté Tokodi ff9ff8f36c
Update doxygen and fix documentation (#5106)
Update Doxyfile to version 1.9.1

Re-enable doxygen CI checker

Fix some regular comments that should have been doc comments

Document void return types for some inline functions explicitly

Move start of some doxygen groups so they are included always, and not left
out of certain ifdefs

Ignore some doxygen warnings:
    Member (function) is not documented in headers
    Documented empty return type in headers
    Argument has multiple @param documentation sections

JerryScript-DCO-1.0-Signed-off-by: Máté Tokodi mate.tokodi@szteszoftver.hu
2023-11-15 09:49:04 +01:00

3457 lines
111 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-objects.h"
#include "ecma-arguments-object.h"
#include "ecma-array-object.h"
#include "ecma-bigint.h"
#include "ecma-builtin-helpers.h"
#include "ecma-builtins.h"
#include "ecma-exceptions.h"
#include "ecma-function-object.h"
#include "ecma-gc.h"
#include "ecma-globals.h"
#include "ecma-helpers.h"
#include "ecma-lcache.h"
#include "ecma-lex-env.h"
#include "ecma-objects-general.h"
#include "ecma-proxy-object.h"
#include "ecma-string-object.h"
#include "jcontext.h"
#if JERRY_BUILTIN_TYPEDARRAY
#include "ecma-arraybuffer-object.h"
#include "ecma-typedarray-object.h"
#endif /* JERRY_BUILTIN_TYPEDARRAY */
/** \addtogroup ecma ECMA
* @{
*
* \addtogroup ecmaobjectsinternalops ECMA objects' operations
* @{
*/
/**
* Hash bitmap size for ecma objects
*/
#define ECMA_OBJECT_HASH_BITMAP_SIZE 256
/**
* Assert that specified object type value is valid
*
* @param type object's implementation-defined type
*/
#ifndef JERRY_NDEBUG
#define JERRY_ASSERT_OBJECT_TYPE_IS_VALID(type) JERRY_ASSERT (type < ECMA_OBJECT_TYPE__MAX);
#else /* JERRY_NDEBUG */
#define JERRY_ASSERT_OBJECT_TYPE_IS_VALID(type)
#endif /* !JERRY_NDEBUG */
/**
* [[GetOwnProperty]] ecma object's operation
*
* See also:
* ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8
*
* @return pointer to a property - if it exists,
* NULL (i.e. ecma-undefined) - otherwise.
*/
ecma_property_t
ecma_op_object_get_own_property (ecma_object_t *object_p, /**< the object */
ecma_string_t *property_name_p, /**< property name */
ecma_property_ref_t *property_ref_p, /**< property reference */
uint32_t options) /**< option bits */
{
JERRY_ASSERT (object_p != NULL && !ecma_is_lexical_environment (object_p));
#if JERRY_BUILTIN_PROXY
JERRY_ASSERT (!ECMA_OBJECT_IS_PROXY (object_p));
#endif /* JERRY_BUILTIN_PROXY */
JERRY_ASSERT (property_name_p != NULL);
JERRY_ASSERT (options == ECMA_PROPERTY_GET_NO_OPTIONS || property_ref_p != NULL);
ecma_object_base_type_t base_type = ecma_get_object_base_type (object_p);
switch (base_type)
{
case ECMA_OBJECT_BASE_TYPE_CLASS:
{
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
switch (ext_object_p->u.cls.type)
{
case ECMA_OBJECT_CLASS_STRING:
{
if (ecma_string_is_length (property_name_p))
{
if (options & ECMA_PROPERTY_GET_VALUE)
{
ecma_value_t prim_value_p = ext_object_p->u.cls.u3.value;
ecma_string_t *prim_value_str_p = ecma_get_string_from_value (prim_value_p);
lit_utf8_size_t length = ecma_string_get_length (prim_value_str_p);
property_ref_p->virtual_value = ecma_make_uint32_value (length);
}
return ECMA_PROPERTY_VIRTUAL;
}
uint32_t index = ecma_string_get_array_index (property_name_p);
if (index != ECMA_STRING_NOT_ARRAY_INDEX)
{
ecma_value_t prim_value_p = ext_object_p->u.cls.u3.value;
ecma_string_t *prim_value_str_p = ecma_get_string_from_value (prim_value_p);
if (index < ecma_string_get_length (prim_value_str_p))
{
if (options & ECMA_PROPERTY_GET_VALUE)
{
ecma_char_t char_at_idx = ecma_string_get_char_at_pos (prim_value_str_p, index);
ecma_string_t *char_str_p = ecma_new_ecma_string_from_code_unit (char_at_idx);
property_ref_p->virtual_value = ecma_make_string_value (char_str_p);
}
return ECMA_PROPERTY_FLAG_ENUMERABLE | ECMA_PROPERTY_VIRTUAL;
}
}
break;
}
#if JERRY_BUILTIN_TYPEDARRAY
/* ES2015 9.4.5.1 */
case ECMA_OBJECT_CLASS_TYPEDARRAY:
{
if (ecma_prop_name_is_symbol (property_name_p))
{
break;
}
uint32_t index = ecma_string_get_array_index (property_name_p);
if (index == ECMA_STRING_NOT_ARRAY_INDEX)
{
JERRY_ASSERT (index == UINT32_MAX);
if (!ecma_typedarray_is_element_index (property_name_p))
{
break;
}
}
ecma_typedarray_info_t info = ecma_typedarray_get_info (object_p);
ecma_value_t value = ecma_get_typedarray_element (&info, index);
if (ECMA_IS_VALUE_ERROR (value))
{
return ECMA_PROPERTY_TYPE_NOT_FOUND_AND_THROW;
}
if (JERRY_UNLIKELY (ecma_is_value_undefined (value)))
{
return ECMA_PROPERTY_TYPE_NOT_FOUND_AND_STOP;
}
if (options & ECMA_PROPERTY_GET_VALUE)
{
property_ref_p->virtual_value = value;
}
else
{
ecma_fast_free_value (value);
}
return ECMA_PROPERTY_ENUMERABLE_WRITABLE | ECMA_PROPERTY_VIRTUAL;
}
#endif /* JERRY_BUILTIN_TYPEDARRAY */
#if JERRY_MODULE_SYSTEM
case ECMA_OBJECT_CLASS_MODULE_NAMESPACE:
{
if (JERRY_UNLIKELY (ecma_prop_name_is_symbol (property_name_p)))
{
if (!ecma_op_compare_string_to_global_symbol (property_name_p, LIT_GLOBAL_SYMBOL_TO_STRING_TAG))
{
return ECMA_PROPERTY_TYPE_NOT_FOUND_AND_STOP;
}
/* ECMA-262 v11, 26.3.1 */
if (options & ECMA_PROPERTY_GET_VALUE)
{
property_ref_p->virtual_value = ecma_make_magic_string_value (LIT_MAGIC_STRING_MODULE_UL);
}
return ECMA_PROPERTY_VIRTUAL;
}
ecma_property_t *property_p = ecma_find_named_property (object_p, property_name_p);
if (property_p == NULL)
{
return ECMA_PROPERTY_TYPE_NOT_FOUND_AND_STOP;
}
JERRY_ASSERT (ECMA_PROPERTY_IS_RAW (*property_p));
if (*property_p & ECMA_PROPERTY_FLAG_DATA)
{
if (options & ECMA_PROPERTY_GET_EXT_REFERENCE)
{
((ecma_extended_property_ref_t *) property_ref_p)->property_p = property_p;
}
if (property_ref_p != NULL)
{
property_ref_p->value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
}
return *property_p;
}
if (options & ECMA_PROPERTY_GET_VALUE)
{
ecma_property_value_t *prop_value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
prop_value_p = ecma_get_property_value_from_named_reference (prop_value_p);
property_ref_p->virtual_value = ecma_fast_copy_value (prop_value_p->value);
}
return ECMA_PROPERTY_ENUMERABLE_WRITABLE | ECMA_PROPERTY_VIRTUAL;
}
#endif /* JERRY_MODULE_SYSTEM */
}
break;
}
case ECMA_OBJECT_BASE_TYPE_ARRAY:
{
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
if (ecma_string_is_length (property_name_p))
{
if (options & ECMA_PROPERTY_GET_VALUE)
{
property_ref_p->virtual_value = ecma_make_uint32_value (ext_object_p->u.array.length);
}
uint32_t length_prop = ext_object_p->u.array.length_prop_and_hole_count;
return length_prop & (ECMA_PROPERTY_FLAG_WRITABLE | ECMA_PROPERTY_VIRTUAL);
}
if (ecma_op_array_is_fast_array (ext_object_p))
{
uint32_t index = ecma_string_get_array_index (property_name_p);
if (index != ECMA_STRING_NOT_ARRAY_INDEX)
{
if (JERRY_LIKELY (index < ext_object_p->u.array.length))
{
ecma_value_t *values_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, object_p->u1.property_list_cp);
if (ecma_is_value_array_hole (values_p[index]))
{
return ECMA_PROPERTY_TYPE_NOT_FOUND;
}
if (options & ECMA_PROPERTY_GET_VALUE)
{
property_ref_p->virtual_value = ecma_fast_copy_value (values_p[index]);
}
return ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE | ECMA_PROPERTY_VIRTUAL;
}
}
return ECMA_PROPERTY_TYPE_NOT_FOUND;
}
break;
}
default:
{
break;
}
}
ecma_property_t *property_p = ecma_find_named_property (object_p, property_name_p);
ecma_object_type_t type = ecma_get_object_type (object_p);
if (property_p == NULL)
{
switch (type)
{
case ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION:
{
if (ecma_builtin_function_is_routine (object_p))
{
property_p = ecma_builtin_routine_try_to_instantiate_property (object_p, property_name_p);
break;
}
/* FALLTHRU */
}
case ECMA_OBJECT_TYPE_BUILT_IN_GENERAL:
case ECMA_OBJECT_TYPE_BUILT_IN_CLASS:
case ECMA_OBJECT_TYPE_BUILT_IN_ARRAY:
{
property_p = ecma_builtin_try_to_instantiate_property (object_p, property_name_p);
break;
}
case ECMA_OBJECT_TYPE_CLASS:
{
if (((ecma_extended_object_t *) object_p)->u.cls.type == ECMA_OBJECT_CLASS_ARGUMENTS)
{
property_p = ecma_op_arguments_object_try_to_lazy_instantiate_property (object_p, property_name_p);
}
break;
}
case ECMA_OBJECT_TYPE_FUNCTION:
{
/* Get prototype physical property. */
property_p = ecma_op_function_try_to_lazy_instantiate_property (object_p, property_name_p);
break;
}
case ECMA_OBJECT_TYPE_NATIVE_FUNCTION:
{
property_p = ecma_op_external_function_try_to_lazy_instantiate_property (object_p, property_name_p);
break;
}
case ECMA_OBJECT_TYPE_BOUND_FUNCTION:
{
property_p = ecma_op_bound_function_try_to_lazy_instantiate_property (object_p, property_name_p);
break;
}
default:
{
break;
}
}
if (property_p == NULL)
{
return ECMA_PROPERTY_TYPE_NOT_FOUND;
}
}
else if (type == ECMA_OBJECT_TYPE_CLASS
&& ((ecma_extended_object_t *) object_p)->u.cls.type == ECMA_OBJECT_CLASS_ARGUMENTS
&& (((ecma_extended_object_t *) object_p)->u.cls.u1.arguments_flags & ECMA_ARGUMENTS_OBJECT_MAPPED))
{
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
uint32_t index = ecma_string_get_array_index (property_name_p);
if (index < ext_object_p->u.cls.u2.formal_params_number)
{
ecma_mapped_arguments_t *mapped_arguments_p = (ecma_mapped_arguments_t *) ext_object_p;
ecma_value_t *argv_p = (ecma_value_t *) (mapped_arguments_p + 1);
if (!ecma_is_value_empty (argv_p[index]) && argv_p[index] != ECMA_VALUE_ARGUMENT_NO_TRACK)
{
#if JERRY_LCACHE
/* Mapped arguments initialized properties MUST not be lcached */
if (ecma_is_property_lcached (property_p))
{
jmem_cpointer_t prop_name_cp;
if (JERRY_UNLIKELY (ECMA_IS_DIRECT_STRING (property_name_p)))
{
prop_name_cp = (jmem_cpointer_t) ECMA_GET_DIRECT_STRING_VALUE (property_name_p);
}
else
{
ECMA_SET_NON_NULL_POINTER (prop_name_cp, property_name_p);
}
ecma_lcache_invalidate (object_p, prop_name_cp, property_p);
}
#endif /* JERRY_LCACHE */
ecma_string_t *name_p = ecma_op_arguments_object_get_formal_parameter (mapped_arguments_p, index);
ecma_object_t *lex_env_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, mapped_arguments_p->lex_env);
ecma_value_t binding_value = ecma_op_get_binding_value (lex_env_p, name_p, true);
ecma_named_data_property_assign_value (object_p, ECMA_PROPERTY_VALUE_PTR (property_p), binding_value);
ecma_free_value (binding_value);
}
}
}
if (options & ECMA_PROPERTY_GET_EXT_REFERENCE)
{
((ecma_extended_property_ref_t *) property_ref_p)->property_p = property_p;
}
if (property_ref_p != NULL)
{
property_ref_p->value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
}
return *property_p;
} /* ecma_op_object_get_own_property */
/**
* Generic [[HasProperty]] operation
*
* See also:
* ECMAScript v6, 9.1.7.1
*
* @return ECMA_VALUE_ERROR - if the operation fails
* ECMA_VALUE_{TRUE_FALSE} - whether the property is found
*/
extern inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE
ecma_op_object_has_property (ecma_object_t *object_p, /**< the object */
ecma_string_t *property_name_p) /**< property name */
{
while (true)
{
#if JERRY_BUILTIN_PROXY
if (ECMA_OBJECT_IS_PROXY (object_p))
{
return ecma_proxy_object_has (object_p, property_name_p);
}
#endif /* JERRY_BUILTIN_PROXY */
/* 2 - 3. */
ecma_property_t property =
ecma_op_object_get_own_property (object_p, property_name_p, NULL, ECMA_PROPERTY_GET_NO_OPTIONS);
if (property != ECMA_PROPERTY_TYPE_NOT_FOUND)
{
#if JERRY_BUILTIN_TYPEDARRAY
if (JERRY_UNLIKELY (property == ECMA_PROPERTY_TYPE_NOT_FOUND_AND_THROW))
{
return ECMA_VALUE_ERROR;
}
#endif /* JERRY_BUILTIN_TYPEDARRAY */
JERRY_ASSERT (property == ECMA_PROPERTY_TYPE_NOT_FOUND_AND_STOP || ECMA_PROPERTY_IS_FOUND (property));
return ecma_make_boolean_value (property != ECMA_PROPERTY_TYPE_NOT_FOUND_AND_STOP);
}
jmem_cpointer_t proto_cp = ecma_op_ordinary_object_get_prototype_of (object_p);
/* 7. */
if (proto_cp == JMEM_CP_NULL)
{
return ECMA_VALUE_FALSE;
}
object_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp);
}
} /* ecma_op_object_has_property */
/**
* Search the value corresponding to a property name
*
* Note: search includes prototypes
*
* @return ecma value if property is found
* ECMA_VALUE_NOT_FOUND if property is not found
* Returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_op_object_find_own (ecma_value_t base_value, /**< base value */
ecma_object_t *object_p, /**< target object */
ecma_string_t *property_name_p) /**< property name */
{
JERRY_ASSERT (object_p != NULL && !ecma_is_lexical_environment (object_p));
JERRY_ASSERT (property_name_p != NULL);
JERRY_ASSERT (!ECMA_OBJECT_IS_PROXY (object_p));
ecma_object_base_type_t base_type = ecma_get_object_base_type (object_p);
switch (base_type)
{
case ECMA_OBJECT_BASE_TYPE_CLASS:
{
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
switch (ext_object_p->u.cls.type)
{
case ECMA_OBJECT_CLASS_STRING:
{
if (ecma_string_is_length (property_name_p))
{
ecma_value_t prim_value_p = ext_object_p->u.cls.u3.value;
ecma_string_t *prim_value_str_p = ecma_get_string_from_value (prim_value_p);
lit_utf8_size_t length = ecma_string_get_length (prim_value_str_p);
return ecma_make_uint32_value (length);
}
uint32_t index = ecma_string_get_array_index (property_name_p);
if (index != ECMA_STRING_NOT_ARRAY_INDEX)
{
ecma_value_t prim_value_p = ext_object_p->u.cls.u3.value;
ecma_string_t *prim_value_str_p = ecma_get_string_from_value (prim_value_p);
if (index < ecma_string_get_length (prim_value_str_p))
{
ecma_char_t char_at_idx = ecma_string_get_char_at_pos (prim_value_str_p, index);
return ecma_make_string_value (ecma_new_ecma_string_from_code_unit (char_at_idx));
}
}
break;
}
case ECMA_OBJECT_CLASS_ARGUMENTS:
{
if (!(ext_object_p->u.cls.u1.arguments_flags & ECMA_ARGUMENTS_OBJECT_MAPPED))
{
break;
}
uint32_t index = ecma_string_get_array_index (property_name_p);
if (index < ext_object_p->u.cls.u2.formal_params_number)
{
ecma_mapped_arguments_t *mapped_arguments_p = (ecma_mapped_arguments_t *) ext_object_p;
ecma_value_t *argv_p = (ecma_value_t *) (mapped_arguments_p + 1);
if (!ecma_is_value_empty (argv_p[index]) && argv_p[index] != ECMA_VALUE_ARGUMENT_NO_TRACK)
{
ecma_string_t *name_p = ecma_op_arguments_object_get_formal_parameter (mapped_arguments_p, index);
ecma_object_t *lex_env_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, mapped_arguments_p->lex_env);
return ecma_op_get_binding_value (lex_env_p, name_p, true);
}
}
break;
}
#if JERRY_BUILTIN_TYPEDARRAY
/* ES2015 9.4.5.4 */
case ECMA_OBJECT_CLASS_TYPEDARRAY:
{
if (ecma_prop_name_is_symbol (property_name_p))
{
break;
}
uint32_t index = ecma_string_get_array_index (property_name_p);
if (index == ECMA_STRING_NOT_ARRAY_INDEX)
{
JERRY_ASSERT (index == UINT32_MAX);
if (!ecma_typedarray_is_element_index (property_name_p))
{
break;
}
}
ecma_typedarray_info_t info = ecma_typedarray_get_info (object_p);
return ecma_get_typedarray_element (&info, index);
}
#endif /* JERRY_BUILTIN_TYPEDARRAY */
#if JERRY_MODULE_SYSTEM
case ECMA_OBJECT_CLASS_MODULE_NAMESPACE:
{
if (JERRY_UNLIKELY (ecma_prop_name_is_symbol (property_name_p)))
{
/* ECMA-262 v11, 26.3.1 */
if (ecma_op_compare_string_to_global_symbol (property_name_p, LIT_GLOBAL_SYMBOL_TO_STRING_TAG))
{
return ecma_make_magic_string_value (LIT_MAGIC_STRING_MODULE_UL);
}
return ECMA_VALUE_NOT_FOUND;
}
ecma_property_t *property_p = ecma_find_named_property (object_p, property_name_p);
if (property_p == NULL)
{
return ECMA_VALUE_NOT_FOUND;
}
JERRY_ASSERT (ECMA_PROPERTY_IS_RAW (*property_p));
ecma_property_value_t *prop_value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
if (!(*property_p & ECMA_PROPERTY_FLAG_DATA))
{
prop_value_p = ecma_get_property_value_from_named_reference (prop_value_p);
if (JERRY_UNLIKELY (prop_value_p->value == ECMA_VALUE_UNINITIALIZED))
{
return ecma_raise_reference_error (ECMA_ERR_LET_CONST_NOT_INITIALIZED);
}
}
return ecma_fast_copy_value (prop_value_p->value);
}
#endif /* JERRY_MODULE_SYSTEM */
}
break;
}
case ECMA_OBJECT_BASE_TYPE_ARRAY:
{
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
if (ecma_string_is_length (property_name_p))
{
return ecma_make_uint32_value (ext_object_p->u.array.length);
}
if (JERRY_LIKELY (ecma_op_array_is_fast_array (ext_object_p)))
{
uint32_t index = ecma_string_get_array_index (property_name_p);
if (JERRY_LIKELY (index != ECMA_STRING_NOT_ARRAY_INDEX))
{
if (JERRY_LIKELY (index < ext_object_p->u.array.length))
{
ecma_value_t *values_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, object_p->u1.property_list_cp);
return (ecma_is_value_array_hole (values_p[index]) ? ECMA_VALUE_NOT_FOUND
: ecma_fast_copy_value (values_p[index]));
}
}
return ECMA_VALUE_NOT_FOUND;
}
break;
}
default:
{
break;
}
}
ecma_property_t *property_p = ecma_find_named_property (object_p, property_name_p);
if (property_p == NULL)
{
switch (ecma_get_object_type (object_p))
{
case ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION:
{
if (ecma_builtin_function_is_routine (object_p))
{
property_p = ecma_builtin_routine_try_to_instantiate_property (object_p, property_name_p);
break;
}
/* FALLTHRU */
}
case ECMA_OBJECT_TYPE_BUILT_IN_GENERAL:
case ECMA_OBJECT_TYPE_BUILT_IN_CLASS:
case ECMA_OBJECT_TYPE_BUILT_IN_ARRAY:
{
property_p = ecma_builtin_try_to_instantiate_property (object_p, property_name_p);
break;
}
case ECMA_OBJECT_TYPE_CLASS:
{
if (((ecma_extended_object_t *) object_p)->u.cls.type == ECMA_OBJECT_CLASS_ARGUMENTS)
{
property_p = ecma_op_arguments_object_try_to_lazy_instantiate_property (object_p, property_name_p);
}
break;
}
case ECMA_OBJECT_TYPE_FUNCTION:
{
/* Get prototype physical property. */
property_p = ecma_op_function_try_to_lazy_instantiate_property (object_p, property_name_p);
break;
}
case ECMA_OBJECT_TYPE_NATIVE_FUNCTION:
{
property_p = ecma_op_external_function_try_to_lazy_instantiate_property (object_p, property_name_p);
break;
}
case ECMA_OBJECT_TYPE_BOUND_FUNCTION:
{
property_p = ecma_op_bound_function_try_to_lazy_instantiate_property (object_p, property_name_p);
break;
}
default:
{
break;
}
}
if (property_p == NULL)
{
return ECMA_VALUE_NOT_FOUND;
}
}
JERRY_ASSERT (ECMA_PROPERTY_IS_RAW (*property_p));
ecma_property_value_t *prop_value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
if (*property_p & ECMA_PROPERTY_FLAG_DATA)
{
return ecma_fast_copy_value (prop_value_p->value);
}
ecma_getter_setter_pointers_t *get_set_pair_p = ecma_get_named_accessor_property (prop_value_p);
if (get_set_pair_p->getter_cp == JMEM_CP_NULL)
{
return ECMA_VALUE_UNDEFINED;
}
ecma_object_t *getter_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, get_set_pair_p->getter_cp);
return ecma_op_function_call (getter_p, base_value, NULL, 0);
} /* ecma_op_object_find_own */
/**
* Search the value corresponding to a property index
*
* Note: this method falls back to the general ecma_op_object_find
*
* @return ecma value if property is found
* ECMA_VALUE_NOT_FOUND if property is not found
* Returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_op_object_find_by_index (ecma_object_t *object_p, /**< the object */
ecma_length_t index) /**< property index */
{
if (JERRY_LIKELY (index <= ECMA_DIRECT_STRING_MAX_IMM))
{
return ecma_op_object_find (object_p, ECMA_CREATE_DIRECT_UINT32_STRING (index));
}
ecma_string_t *index_str_p = ecma_new_ecma_string_from_length (index);
ecma_value_t ret_value = ecma_op_object_find (object_p, index_str_p);
ecma_deref_ecma_string (index_str_p);
return ret_value;
} /* ecma_op_object_find_by_index */
/**
* Search the value corresponding to a property name
*
* Note: search includes prototypes
*
* @return ecma value if property is found
* ECMA_VALUE_NOT_FOUND if property is not found
* Returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_op_object_find (ecma_object_t *object_p, /**< the object */
ecma_string_t *property_name_p) /**< property name */
{
ecma_value_t base_value = ecma_make_object_value (object_p);
while (true)
{
#if JERRY_BUILTIN_PROXY
if (ECMA_OBJECT_IS_PROXY (object_p))
{
return ecma_proxy_object_find (object_p, property_name_p);
}
#endif /* JERRY_BUILTIN_PROXY */
ecma_value_t value = ecma_op_object_find_own (base_value, object_p, property_name_p);
if (ecma_is_value_found (value))
{
return value;
}
if (object_p->u2.prototype_cp == JMEM_CP_NULL)
{
break;
}
object_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, object_p->u2.prototype_cp);
}
return ECMA_VALUE_NOT_FOUND;
} /* ecma_op_object_find */
/**
* [[Get]] operation of ecma object
*
* This function returns the value of a named property, or undefined
* if the property is not found in the prototype chain. If the property
* is an accessor, it calls the "get" callback function and returns
* with its result (including error throws).
*
* See also:
* ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8
*
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
extern inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE
ecma_op_object_get (ecma_object_t *object_p, /**< the object */
ecma_string_t *property_name_p) /**< property name */
{
return ecma_op_object_get_with_receiver (object_p, property_name_p, ecma_make_object_value (object_p));
} /* ecma_op_object_get */
/**
* [[Get]] operation of ecma object with the specified receiver
*
* This function returns the value of a named property, or undefined
* if the property is not found in the prototype chain. If the property
* is an accessor, it calls the "get" callback function and returns
* with its result (including error throws).
*
* See also:
* ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8
*
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_op_object_get_with_receiver (ecma_object_t *object_p, /**< the object */
ecma_string_t *property_name_p, /**< property name */
ecma_value_t receiver) /**< receiver to invoke getter function */
{
while (true)
{
#if JERRY_BUILTIN_PROXY
if (ECMA_OBJECT_IS_PROXY (object_p))
{
return ecma_proxy_object_get (object_p, property_name_p, receiver);
}
#endif /* JERRY_BUILTIN_PROXY */
ecma_value_t value = ecma_op_object_find_own (receiver, object_p, property_name_p);
if (ecma_is_value_found (value))
{
return value;
}
jmem_cpointer_t proto_cp = ecma_op_ordinary_object_get_prototype_of (object_p);
if (proto_cp == JMEM_CP_NULL)
{
break;
}
object_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp);
}
return ECMA_VALUE_UNDEFINED;
} /* ecma_op_object_get_with_receiver */
/**
* [[Get]] operation of ecma object specified for property index
*
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_op_object_get_by_index (ecma_object_t *object_p, /**< the object */
ecma_length_t index) /**< property index */
{
if (JERRY_LIKELY (index <= ECMA_DIRECT_STRING_MAX_IMM))
{
return ecma_op_object_get (object_p, ECMA_CREATE_DIRECT_UINT32_STRING (index));
}
ecma_string_t *index_str_p = ecma_new_ecma_string_from_length (index);
ecma_value_t ret_value = ecma_op_object_get (object_p, index_str_p);
ecma_deref_ecma_string (index_str_p);
return ret_value;
} /* ecma_op_object_get_by_index */
/**
* Perform ToLength(O.[[Get]]("length")) operation
*
* The property is converted to uint32 during the operation
*
* @return ECMA_VALUE_ERROR - if there was any error during the operation
* ECMA_VALUE_EMPTY - otherwise
*/
ecma_value_t
ecma_op_object_get_length (ecma_object_t *object_p, /**< the object */
ecma_length_t *length_p) /**< [out] length value converted to uint32 */
{
if (JERRY_LIKELY (ecma_get_object_base_type (object_p) == ECMA_OBJECT_BASE_TYPE_ARRAY))
{
*length_p = (ecma_length_t) ecma_array_get_length (object_p);
return ECMA_VALUE_EMPTY;
}
ecma_value_t len_value = ecma_op_object_get_by_magic_id (object_p, LIT_MAGIC_STRING_LENGTH);
ecma_value_t len_number = ecma_op_to_length (len_value, length_p);
ecma_free_value (len_value);
JERRY_ASSERT (ECMA_IS_VALUE_ERROR (len_number) || ecma_is_value_empty (len_number));
return len_number;
} /* ecma_op_object_get_length */
/**
* [[Get]] operation of ecma object where the property name is a magic string
*
* This function returns the value of a named property, or undefined
* if the property is not found in the prototype chain. If the property
* is an accessor, it calls the "get" callback function and returns
* with its result (including error throws).
*
* See also:
* ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8
*
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
extern inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE
ecma_op_object_get_by_magic_id (ecma_object_t *object_p, /**< the object */
lit_magic_string_id_t property_id) /**< property magic string id */
{
return ecma_op_object_get (object_p, ecma_get_magic_string (property_id));
} /* ecma_op_object_get_by_magic_id */
/**
* Descriptor string for each global symbol
*/
static const uint16_t ecma_global_symbol_descriptions[] = {
LIT_MAGIC_STRING_ASYNC_ITERATOR, LIT_MAGIC_STRING_HAS_INSTANCE, LIT_MAGIC_STRING_IS_CONCAT_SPREADABLE,
LIT_MAGIC_STRING_ITERATOR, LIT_MAGIC_STRING_MATCH, LIT_MAGIC_STRING_REPLACE,
LIT_MAGIC_STRING_SEARCH, LIT_MAGIC_STRING_SPECIES, LIT_MAGIC_STRING_SPLIT,
LIT_MAGIC_STRING_TO_PRIMITIVE, LIT_MAGIC_STRING_TO_STRING_TAG, LIT_MAGIC_STRING_UNSCOPABLES,
LIT_MAGIC_STRING_MATCH_ALL,
};
JERRY_STATIC_ASSERT (sizeof (ecma_global_symbol_descriptions) / sizeof (uint16_t) == ECMA_BUILTIN_GLOBAL_SYMBOL_COUNT,
ecma_global_symbol_descriptions_must_have_global_symbol_count_elements);
/**
* [[Get]] a well-known symbol by the given property id
*
* @return pointer to the requested well-known symbol
*/
ecma_string_t *
ecma_op_get_global_symbol (lit_magic_string_id_t property_id) /**< property symbol id */
{
JERRY_ASSERT (LIT_IS_GLOBAL_SYMBOL (property_id));
uint32_t symbol_index = (uint32_t) property_id - (uint32_t) LIT_GLOBAL_SYMBOL__FIRST;
jmem_cpointer_t symbol_cp = JERRY_CONTEXT (global_symbols_cp)[symbol_index];
if (symbol_cp != JMEM_CP_NULL)
{
ecma_string_t *symbol_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, symbol_cp);
ecma_ref_ecma_string (symbol_p);
return symbol_p;
}
ecma_string_t *symbol_dot_p = ecma_get_magic_string (LIT_MAGIC_STRING_SYMBOL_DOT_UL);
uint16_t description = ecma_global_symbol_descriptions[symbol_index];
ecma_string_t *name_p = ecma_get_magic_string ((lit_magic_string_id_t) description);
ecma_string_t *descriptor_p = ecma_concat_ecma_strings (symbol_dot_p, name_p);
ecma_string_t *symbol_p = ecma_new_symbol_from_descriptor_string (ecma_make_string_value (descriptor_p));
symbol_p->u.hash = (uint16_t) ((property_id << ECMA_SYMBOL_FLAGS_SHIFT) | ECMA_SYMBOL_FLAG_GLOBAL);
ECMA_SET_NON_NULL_POINTER (JERRY_CONTEXT (global_symbols_cp)[symbol_index], symbol_p);
ecma_ref_ecma_string (symbol_p);
return symbol_p;
} /* ecma_op_get_global_symbol */
/**
* Checks whether the string equals to the global symbol.
*
* @return true - if the string equals to the global symbol
* false - otherwise
*/
bool
ecma_op_compare_string_to_global_symbol (ecma_string_t *string_p, /**< string to compare */
lit_magic_string_id_t property_id) /**< property symbol id */
{
JERRY_ASSERT (LIT_IS_GLOBAL_SYMBOL (property_id));
uint32_t symbol_index = (uint32_t) property_id - (uint32_t) LIT_GLOBAL_SYMBOL__FIRST;
jmem_cpointer_t symbol_cp = JERRY_CONTEXT (global_symbols_cp)[symbol_index];
return (symbol_cp != JMEM_CP_NULL && string_p == ECMA_GET_NON_NULL_POINTER (ecma_string_t, symbol_cp));
} /* ecma_op_compare_string_to_global_symbol */
/**
* [[Get]] operation of ecma object where the property is a well-known symbol
*
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_op_object_get_by_symbol_id (ecma_object_t *object_p, /**< the object */
lit_magic_string_id_t property_id) /**< property symbol id */
{
ecma_string_t *symbol_p = ecma_op_get_global_symbol (property_id);
ecma_value_t ret_value = ecma_op_object_get (object_p, symbol_p);
ecma_deref_ecma_string (symbol_p);
return ret_value;
} /* ecma_op_object_get_by_symbol_id */
/**
* GetMethod operation
*
* See also: ECMA-262 v6, 7.3.9
*
* Note:
* Returned value must be freed with ecma_free_value.
*
* @return iterator function object - if success
* raised error - otherwise
*/
static ecma_value_t
ecma_op_get_method (ecma_value_t value, /**< ecma value */
ecma_string_t *prop_name_p) /**< property name */
{
/* 2. */
ecma_value_t obj_value = ecma_op_to_object (value);
if (ECMA_IS_VALUE_ERROR (obj_value))
{
return obj_value;
}
ecma_object_t *obj_p = ecma_get_object_from_value (obj_value);
ecma_value_t func;
func = ecma_op_object_get (obj_p, prop_name_p);
ecma_deref_object (obj_p);
/* 3. */
if (ECMA_IS_VALUE_ERROR (func))
{
return func;
}
/* 4. */
if (ecma_is_value_undefined (func) || ecma_is_value_null (func))
{
return ECMA_VALUE_UNDEFINED;
}
/* 5. */
if (!ecma_op_is_callable (func))
{
ecma_free_value (func);
return ecma_raise_type_error (ECMA_ERR_ITERATOR_IS_NOT_CALLABLE);
}
/* 6. */
return func;
} /* ecma_op_get_method */
/**
* GetMethod operation when the property is a well-known symbol
*
* See also: ECMA-262 v6, 7.3.9
*
* Note:
* Returned value must be freed with ecma_free_value.
*
* @return iterator function object - if success
* raised error - otherwise
*/
ecma_value_t
ecma_op_get_method_by_symbol_id (ecma_value_t value, /**< ecma value */
lit_magic_string_id_t symbol_id) /**< property symbol id */
{
ecma_string_t *prop_name_p = ecma_op_get_global_symbol (symbol_id);
ecma_value_t ret_value = ecma_op_get_method (value, prop_name_p);
ecma_deref_ecma_string (prop_name_p);
return ret_value;
} /* ecma_op_get_method_by_symbol_id */
/**
* GetMethod operation when the property is a magic string
*
* See also: ECMA-262 v6, 7.3.9
*
* Note:
* Returned value must be freed with ecma_free_value.
*
* @return iterator function object - if success
* raised error - otherwise
*/
ecma_value_t
ecma_op_get_method_by_magic_id (ecma_value_t value, /**< ecma value */
lit_magic_string_id_t magic_id) /**< property magic id */
{
return ecma_op_get_method (value, ecma_get_magic_string (magic_id));
} /* ecma_op_get_method_by_magic_id */
/**
* [[Put]] ecma general object's operation specialized for property index
*
* Note: This function falls back to the general ecma_op_object_put
*
* @return ecma value
* The returned value must be freed with ecma_free_value.
*/
ecma_value_t
ecma_op_object_put_by_index (ecma_object_t *object_p, /**< the object */
ecma_length_t index, /**< property index */
ecma_value_t value, /**< ecma value */
bool is_throw) /**< flag that controls failure handling */
{
if (JERRY_LIKELY (index <= ECMA_DIRECT_STRING_MAX_IMM))
{
return ecma_op_object_put (object_p, ECMA_CREATE_DIRECT_UINT32_STRING (index), value, is_throw);
}
ecma_string_t *index_str_p = ecma_new_ecma_string_from_length (index);
ecma_value_t ret_value = ecma_op_object_put (object_p, index_str_p, value, is_throw);
ecma_deref_ecma_string (index_str_p);
return ret_value;
} /* ecma_op_object_put_by_index */
/**
* [[Put]] ecma general object's operation
*
* See also:
* ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8
* ECMA-262 v5, 8.12.5
* Also incorporates [[CanPut]] ECMA-262 v5, 8.12.4
*
* @return ecma value
* The returned value must be freed with ecma_free_value.
*
* Returns with ECMA_VALUE_TRUE if the operation is
* successful. Otherwise it returns with an error object
* or ECMA_VALUE_FALSE.
*
* Note: even if is_throw is false, the setter can throw an
* error, and this function returns with that error.
*/
extern inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE
ecma_op_object_put (ecma_object_t *object_p, /**< the object */
ecma_string_t *property_name_p, /**< property name */
ecma_value_t value, /**< ecma value */
bool is_throw) /**< flag that controls failure handling */
{
return ecma_op_object_put_with_receiver (object_p,
property_name_p,
value,
ecma_make_object_value (object_p),
is_throw);
} /* ecma_op_object_put */
/**
* [[Set]] ( P, V, Receiver) operation part for ordinary objects
*
* See also: ECMAScript v6, 9.19.9
*
* @return ecma value
* The returned value must be freed with ecma_free_value.
*/
static ecma_value_t
ecma_op_object_put_apply_receiver (ecma_value_t receiver, /**< receiver */
ecma_string_t *property_name_p, /**< property name */
ecma_value_t value, /**< value to set */
bool is_throw) /**< flag that controls failure handling */
{
/* 5.b */
if (!ecma_is_value_object (receiver))
{
return ECMA_REJECT (is_throw, ECMA_ERR_RECEIVER_MUST_BE_AN_OBJECT);
}
ecma_object_t *receiver_obj_p = ecma_get_object_from_value (receiver);
ecma_property_descriptor_t prop_desc;
/* 5.c */
ecma_value_t status = ecma_op_object_get_own_property_descriptor (receiver_obj_p, property_name_p, &prop_desc);
/* 5.d */
if (ECMA_IS_VALUE_ERROR (status))
{
return status;
}
/* 5.e */
if (ecma_is_value_true (status))
{
ecma_value_t result;
/* 5.e.i - 5.e.ii */
if (prop_desc.flags & (JERRY_PROP_IS_GET_DEFINED | JERRY_PROP_IS_SET_DEFINED)
|| !(prop_desc.flags & JERRY_PROP_IS_WRITABLE))
{
result = ecma_raise_property_redefinition (property_name_p, prop_desc.flags);
}
else
{
/* 5.e.iii */
JERRY_ASSERT (prop_desc.flags & JERRY_PROP_IS_VALUE_DEFINED);
ecma_free_value (prop_desc.value);
prop_desc.value = ecma_copy_value (value);
/* 5.e.iv */
result = ecma_op_object_define_own_property (receiver_obj_p, property_name_p, &prop_desc);
if (JERRY_UNLIKELY (ecma_is_value_false (result)))
{
result = ECMA_REJECT (is_throw, ECMA_ERR_PROXY_TRAP_RETURNED_FALSISH);
}
}
ecma_free_property_descriptor (&prop_desc);
return result;
}
#if JERRY_BUILTIN_PROXY
if (ECMA_OBJECT_IS_PROXY (receiver_obj_p))
{
ecma_property_descriptor_t desc;
/* Based on: ES6 9.1.9 [[Set]] 4.d.i. / ES11 9.1.9.2 OrdinarySetWithOwnDescriptor 2.c.i. */
desc.flags = (JERRY_PROP_IS_CONFIGURABLE | JERRY_PROP_IS_CONFIGURABLE_DEFINED | JERRY_PROP_IS_ENUMERABLE
| JERRY_PROP_IS_ENUMERABLE_DEFINED | JERRY_PROP_IS_WRITABLE | JERRY_PROP_IS_WRITABLE_DEFINED
| JERRY_PROP_IS_VALUE_DEFINED);
desc.value = value;
ecma_value_t ret_value = ecma_proxy_object_define_own_property (receiver_obj_p, property_name_p, &desc);
if (JERRY_UNLIKELY (ecma_is_value_false (ret_value)))
{
ret_value = ECMA_REJECT (is_throw, ECMA_ERR_PROXY_TRAP_RETURNED_FALSISH);
}
return ret_value;
}
#endif /* JERRY_BUILTIN_PROXY */
if (JERRY_UNLIKELY (ecma_op_object_is_fast_array (receiver_obj_p)))
{
ecma_fast_array_convert_to_normal (receiver_obj_p);
}
/* 5.f.i */
ecma_property_value_t *new_prop_value_p;
new_prop_value_p = ecma_create_named_data_property (receiver_obj_p,
property_name_p,
ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
NULL);
JERRY_ASSERT (ecma_is_value_undefined (new_prop_value_p->value));
new_prop_value_p->value = ecma_copy_value_if_not_object (value);
return ECMA_VALUE_TRUE;
} /* ecma_op_object_put_apply_receiver */
/**
* [[Put]] ecma general object's operation with given receiver
*
* See also:
* ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8
* ECMA-262 v5, 8.12.5
* ECMA-262 v6, 9.1.9
* Also incorporates [[CanPut]] ECMA-262 v5, 8.12.4
*
* @return ecma value
* The returned value must be freed with ecma_free_value.
*
* Returns with ECMA_VALUE_TRUE if the operation is
* successful. Otherwise it returns with an error object
* or ECMA_VALUE_FALSE.
*
* Note: even if is_throw is false, the setter can throw an
* error, and this function returns with that error.
*/
ecma_value_t
ecma_op_object_put_with_receiver (ecma_object_t *object_p, /**< the object */
ecma_string_t *property_name_p, /**< property name */
ecma_value_t value, /**< ecma value */
ecma_value_t receiver, /**< receiver */
bool is_throw) /**< flag that controls failure handling */
{
JERRY_ASSERT (object_p != NULL && !ecma_is_lexical_environment (object_p));
JERRY_ASSERT (property_name_p != NULL);
#if JERRY_BUILTIN_PROXY
if (ECMA_OBJECT_IS_PROXY (object_p))
{
return ecma_proxy_object_set (object_p, property_name_p, value, receiver, is_throw);
}
#endif /* JERRY_BUILTIN_PROXY */
ecma_object_base_type_t base_type = ecma_get_object_base_type (object_p);
switch (base_type)
{
case ECMA_OBJECT_BASE_TYPE_CLASS:
{
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
switch (ext_object_p->u.cls.type)
{
case ECMA_OBJECT_CLASS_ARGUMENTS:
{
if (!(ext_object_p->u.cls.u1.arguments_flags & ECMA_ARGUMENTS_OBJECT_MAPPED))
{
break;
}
uint32_t index = ecma_string_get_array_index (property_name_p);
if (index < ext_object_p->u.cls.u2.formal_params_number)
{
ecma_mapped_arguments_t *mapped_arguments_p = (ecma_mapped_arguments_t *) ext_object_p;
ecma_value_t *argv_p = (ecma_value_t *) (mapped_arguments_p + 1);
if (!ecma_is_value_empty (argv_p[index]) && argv_p[index] != ECMA_VALUE_ARGUMENT_NO_TRACK)
{
ecma_string_t *name_p = ecma_op_arguments_object_get_formal_parameter (mapped_arguments_p, index);
ecma_object_t *lex_env_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, mapped_arguments_p->lex_env);
ecma_op_set_mutable_binding (lex_env_p, name_p, value, true);
return ECMA_VALUE_TRUE;
}
}
break;
}
#if JERRY_BUILTIN_TYPEDARRAY
/* ES2015 9.4.5.5 */
case ECMA_OBJECT_CLASS_TYPEDARRAY:
{
if (ecma_prop_name_is_symbol (property_name_p))
{
break;
}
uint32_t index = ecma_string_get_array_index (property_name_p);
if (index == ECMA_STRING_NOT_ARRAY_INDEX)
{
JERRY_ASSERT (index == UINT32_MAX);
if (!ecma_typedarray_is_element_index (property_name_p))
{
break;
}
}
ecma_typedarray_info_t info = ecma_typedarray_get_info (object_p);
return ecma_set_typedarray_element (&info, value, index);
}
#endif /* JERRY_BUILTIN_TYPEDARRAY */
#if JERRY_MODULE_SYSTEM
case ECMA_OBJECT_CLASS_MODULE_NAMESPACE:
{
return ecma_raise_readonly_assignment (property_name_p, is_throw);
}
#endif /* JERRY_MODULE_SYSTEM */
}
break;
}
case ECMA_OBJECT_BASE_TYPE_ARRAY:
{
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
if (ecma_string_is_length (property_name_p))
{
if (ecma_is_property_writable ((ecma_property_t) ext_object_p->u.array.length_prop_and_hole_count))
{
return ecma_op_array_object_set_length (object_p, value, 0);
}
return ecma_raise_readonly_assignment (property_name_p, is_throw);
}
if (JERRY_LIKELY (ecma_op_array_is_fast_array (ext_object_p)))
{
uint32_t index = ecma_string_get_array_index (property_name_p);
if (JERRY_UNLIKELY (index == ECMA_STRING_NOT_ARRAY_INDEX))
{
ecma_fast_array_convert_to_normal (object_p);
}
else if (ecma_fast_array_set_property (object_p, index, value))
{
return ECMA_VALUE_TRUE;
}
}
JERRY_ASSERT (!ecma_op_object_is_fast_array (object_p));
break;
}
default:
{
break;
}
}
ecma_property_t *property_p = ecma_find_named_property (object_p, property_name_p);
if (property_p == NULL)
{
switch (ecma_get_object_type (object_p))
{
case ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION:
{
if (ecma_builtin_function_is_routine (object_p))
{
property_p = ecma_builtin_routine_try_to_instantiate_property (object_p, property_name_p);
break;
}
/* FALLTHRU */
}
case ECMA_OBJECT_TYPE_BUILT_IN_GENERAL:
case ECMA_OBJECT_TYPE_BUILT_IN_CLASS:
case ECMA_OBJECT_TYPE_BUILT_IN_ARRAY:
{
property_p = ecma_builtin_try_to_instantiate_property (object_p, property_name_p);
break;
}
case ECMA_OBJECT_TYPE_CLASS:
{
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
switch (ext_object_p->u.cls.type)
{
case ECMA_OBJECT_CLASS_STRING:
{
uint32_t index = ecma_string_get_array_index (property_name_p);
if (index != ECMA_STRING_NOT_ARRAY_INDEX)
{
ecma_value_t prim_value_p = ext_object_p->u.cls.u3.value;
ecma_string_t *prim_value_str_p = ecma_get_string_from_value (prim_value_p);
if (index < ecma_string_get_length (prim_value_str_p))
{
return ecma_raise_readonly_assignment (property_name_p, is_throw);
}
}
break;
}
case ECMA_OBJECT_CLASS_ARGUMENTS:
{
property_p = ecma_op_arguments_object_try_to_lazy_instantiate_property (object_p, property_name_p);
break;
}
}
break;
}
case ECMA_OBJECT_TYPE_FUNCTION:
{
if (ecma_string_is_length (property_name_p))
{
/* Uninitialized 'length' property is non-writable (ECMA-262 v6, 19.2.4.1) */
if (!ECMA_GET_FIRST_BIT_FROM_POINTER_TAG (((ecma_extended_object_t *) object_p)->u.function.scope_cp))
{
return ecma_raise_readonly_assignment (property_name_p, is_throw);
}
}
/* Get prototype physical property. */
property_p = ecma_op_function_try_to_lazy_instantiate_property (object_p, property_name_p);
break;
}
case ECMA_OBJECT_TYPE_NATIVE_FUNCTION:
{
property_p = ecma_op_external_function_try_to_lazy_instantiate_property (object_p, property_name_p);
break;
}
case ECMA_OBJECT_TYPE_BOUND_FUNCTION:
{
property_p = ecma_op_bound_function_try_to_lazy_instantiate_property (object_p, property_name_p);
break;
}
default:
{
break;
}
}
}
jmem_cpointer_t setter_cp = JMEM_CP_NULL;
if (property_p != NULL)
{
JERRY_ASSERT (ECMA_PROPERTY_IS_RAW (*property_p));
if (*property_p & ECMA_PROPERTY_FLAG_DATA)
{
if (ecma_is_property_writable (*property_p))
{
if (ecma_make_object_value (object_p) != receiver)
{
return ecma_op_object_put_apply_receiver (receiver, property_name_p, value, is_throw);
}
/* There is no need for special casing arrays here because changing the
* value of an existing property never changes the length of an array. */
ecma_named_data_property_assign_value (object_p, ECMA_PROPERTY_VALUE_PTR (property_p), value);
return ECMA_VALUE_TRUE;
}
}
else
{
ecma_getter_setter_pointers_t *get_set_pair_p;
get_set_pair_p = ecma_get_named_accessor_property (ECMA_PROPERTY_VALUE_PTR (property_p));
setter_cp = get_set_pair_p->setter_cp;
}
}
else
{
bool create_new_property = true;
jmem_cpointer_t obj_cp;
ECMA_SET_NON_NULL_POINTER (obj_cp, object_p);
ecma_object_t *proto_p = object_p;
while (true)
{
obj_cp = ecma_op_ordinary_object_get_prototype_of (proto_p);
if (obj_cp == JMEM_CP_NULL)
{
break;
}
ecma_property_ref_t property_ref = { NULL };
proto_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, obj_cp);
#if JERRY_BUILTIN_PROXY
if (ECMA_OBJECT_IS_PROXY (proto_p))
{
return ecma_op_object_put_with_receiver (proto_p, property_name_p, value, receiver, is_throw);
}
#endif /* JERRY_BUILTIN_PROXY */
ecma_property_t inherited_property =
ecma_op_object_get_own_property (proto_p, property_name_p, &property_ref, ECMA_PROPERTY_GET_NO_OPTIONS);
if (ECMA_PROPERTY_IS_FOUND (inherited_property))
{
JERRY_ASSERT (ECMA_PROPERTY_IS_NAMED_PROPERTY (inherited_property));
if (!(inherited_property & ECMA_PROPERTY_FLAG_DATA))
{
setter_cp = ecma_get_named_accessor_property (property_ref.value_p)->setter_cp;
create_new_property = false;
break;
}
create_new_property = ecma_is_property_writable (inherited_property);
break;
}
JERRY_ASSERT (inherited_property == ECMA_PROPERTY_TYPE_NOT_FOUND
|| inherited_property == ECMA_PROPERTY_TYPE_NOT_FOUND_AND_STOP);
}
#if JERRY_BUILTIN_PROXY
if (create_new_property && ecma_is_value_object (receiver)
&& ECMA_OBJECT_IS_PROXY (ecma_get_object_from_value (receiver)))
{
return ecma_op_object_put_apply_receiver (receiver, property_name_p, value, is_throw);
}
#endif /* JERRY_BUILTIN_PROXY */
if (create_new_property && ecma_op_ordinary_object_is_extensible (object_p))
{
const ecma_object_base_type_t obj_base_type = ecma_get_object_base_type (object_p);
if (obj_base_type == ECMA_OBJECT_BASE_TYPE_CLASS)
{
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
if (ext_object_p->u.cls.type == ECMA_OBJECT_CLASS_ARGUMENTS
&& ext_object_p->u.cls.u1.arguments_flags & ECMA_ARGUMENTS_OBJECT_MAPPED)
{
const uint32_t flags = ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE | JERRY_PROP_SHOULD_THROW;
return ecma_builtin_helper_def_prop (object_p, property_name_p, value, flags);
}
}
uint32_t index = ecma_string_get_array_index (property_name_p);
if (obj_base_type == ECMA_OBJECT_BASE_TYPE_ARRAY && index != ECMA_STRING_NOT_ARRAY_INDEX)
{
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
if (index < UINT32_MAX && index >= ext_object_p->u.array.length)
{
if (!ecma_is_property_writable ((ecma_property_t) ext_object_p->u.array.length_prop_and_hole_count))
{
return ecma_raise_readonly_assignment (property_name_p, is_throw);
}
ext_object_p->u.array.length = index + 1;
}
}
return ecma_op_object_put_apply_receiver (receiver, property_name_p, value, is_throw);
ecma_property_value_t *new_prop_value_p;
new_prop_value_p = ecma_create_named_data_property (object_p,
property_name_p,
ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
NULL);
JERRY_ASSERT (ecma_is_value_undefined (new_prop_value_p->value));
new_prop_value_p->value = ecma_copy_value_if_not_object (value);
return ECMA_VALUE_TRUE;
}
}
if (setter_cp == JMEM_CP_NULL)
{
return ecma_raise_readonly_assignment (property_name_p, is_throw);
}
ecma_value_t ret_value =
ecma_op_function_call (ECMA_GET_NON_NULL_POINTER (ecma_object_t, setter_cp), receiver, &value, 1);
if (!ECMA_IS_VALUE_ERROR (ret_value))
{
ecma_fast_free_value (ret_value);
ret_value = ECMA_VALUE_TRUE;
}
return ret_value;
} /* ecma_op_object_put_with_receiver */
/**
* [[Delete]] ecma object's operation specialized for property index
*
* Note:
* This method falls back to the general ecma_op_object_delete
*
* @return true - if deleted successfully
* false - or type error otherwise (based in 'is_throw')
*/
ecma_value_t
ecma_op_object_delete_by_index (ecma_object_t *obj_p, /**< the object */
ecma_length_t index, /**< property index */
bool is_throw) /**< flag that controls failure handling */
{
if (JERRY_LIKELY (index <= ECMA_DIRECT_STRING_MAX_IMM))
{
return ecma_op_object_delete (obj_p, ECMA_CREATE_DIRECT_UINT32_STRING (index), is_throw);
;
}
ecma_string_t *index_str_p = ecma_new_ecma_string_from_length (index);
ecma_value_t ret_value = ecma_op_object_delete (obj_p, index_str_p, is_throw);
ecma_deref_ecma_string (index_str_p);
return ret_value;
} /* ecma_op_object_delete_by_index */
/**
* [[Delete]] ecma object's operation
*
* See also:
* ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8
*
* Note:
* returned value must be freed with ecma_free_value
*
* @return true - if deleted successfully
* false - or type error otherwise (based in 'is_throw')
*/
ecma_value_t
ecma_op_object_delete (ecma_object_t *obj_p, /**< the object */
ecma_string_t *property_name_p, /**< property name */
bool is_strict) /**< flag that controls failure handling */
{
JERRY_ASSERT (obj_p != NULL && !ecma_is_lexical_environment (obj_p));
JERRY_ASSERT (property_name_p != NULL);
#if JERRY_BUILTIN_PROXY
if (ECMA_OBJECT_IS_PROXY (obj_p))
{
return ecma_proxy_object_delete_property (obj_p, property_name_p, is_strict);
}
#endif /* JERRY_BUILTIN_PROXY */
JERRY_ASSERT_OBJECT_TYPE_IS_VALID (ecma_get_object_type (obj_p));
return ecma_op_general_object_delete (obj_p, property_name_p, is_strict);
} /* ecma_op_object_delete */
/**
* [[DefaultValue]] ecma object's operation
*
* See also:
* ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8
*
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_op_object_default_value (ecma_object_t *obj_p, /**< the object */
ecma_preferred_type_hint_t hint) /**< hint on preferred result type */
{
JERRY_ASSERT (obj_p != NULL && !ecma_is_lexical_environment (obj_p));
JERRY_ASSERT_OBJECT_TYPE_IS_VALID (ecma_get_object_type (obj_p));
/*
* typedef ecma_property_t * (*default_value_ptr_t) (ecma_object_t *, ecma_string_t *);
* static const default_value_ptr_t default_value [ECMA_OBJECT_TYPE__COUNT] =
* {
* [ECMA_OBJECT_TYPE_GENERAL] = &ecma_op_general_object_default_value,
* [ECMA_OBJECT_TYPE_CLASS] = &ecma_op_general_object_default_value,
* [ECMA_OBJECT_TYPE_FUNCTION] = &ecma_op_general_object_default_value,
* [ECMA_OBJECT_TYPE_NATIVE_FUNCTION] = &ecma_op_general_object_default_value,
* [ECMA_OBJECT_TYPE_ARRAY] = &ecma_op_general_object_default_value,
* [ECMA_OBJECT_TYPE_BOUND_FUNCTION] = &ecma_op_general_object_default_value,
* [ECMA_OBJECT_TYPE_PSEUDO_ARRAY] = &ecma_op_general_object_default_value
* };
*
* return default_value[type] (obj_p, property_name_p);
*/
return ecma_op_general_object_default_value (obj_p, hint);
} /* ecma_op_object_default_value */
/**
* [[DefineOwnProperty]] ecma object's operation
*
* See also:
* ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8
*
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_op_object_define_own_property (ecma_object_t *obj_p, /**< the object */
ecma_string_t *property_name_p, /**< property name */
const ecma_property_descriptor_t *property_desc_p) /**< property
* descriptor */
{
JERRY_ASSERT (obj_p != NULL && !ecma_is_lexical_environment (obj_p));
JERRY_ASSERT (property_name_p != NULL);
const ecma_object_type_t type = ecma_get_object_type (obj_p);
switch (type)
{
case ECMA_OBJECT_TYPE_CLASS:
{
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p;
switch (ext_object_p->u.cls.type)
{
case ECMA_OBJECT_CLASS_ARGUMENTS:
{
return ecma_op_arguments_object_define_own_property (obj_p, property_name_p, property_desc_p);
}
#if JERRY_BUILTIN_TYPEDARRAY
/* ES2015 9.4.5.1 */
case ECMA_OBJECT_CLASS_TYPEDARRAY:
{
return ecma_op_typedarray_define_own_property (obj_p, property_name_p, property_desc_p);
}
#endif /* JERRY_BUILTIN_TYPEDARRAY */
}
break;
}
case ECMA_OBJECT_TYPE_ARRAY:
case ECMA_OBJECT_TYPE_BUILT_IN_ARRAY:
{
return ecma_op_array_object_define_own_property (obj_p, property_name_p, property_desc_p);
}
#if JERRY_BUILTIN_PROXY
case ECMA_OBJECT_TYPE_PROXY:
{
return ecma_proxy_object_define_own_property (obj_p, property_name_p, property_desc_p);
}
#endif /* JERRY_BUILTIN_PROXY */
default:
{
break;
}
}
return ecma_op_general_object_define_own_property (obj_p, property_name_p, property_desc_p);
} /* ecma_op_object_define_own_property */
/**
* Get property descriptor from specified property
*
* depending on the property type the following fields are set:
* - for named data properties: { [Value], [Writable], [Enumerable], [Configurable] };
* - for named accessor properties: { [Get] - if defined,
* [Set] - if defined,
* [Enumerable], [Configurable]
* }.
*
* The output property descriptor will always be initialized to an empty descriptor.
*
* @return ECMA_VALUE_ERROR - if the Proxy.[[GetOwnProperty]] operation raises error
* ECMA_VALUE_{TRUE, FALSE} - if property found or not
*/
ecma_value_t
ecma_op_object_get_own_property_descriptor (ecma_object_t *object_p, /**< the object */
ecma_string_t *property_name_p, /**< property name */
ecma_property_descriptor_t *prop_desc_p) /**< property descriptor */
{
*prop_desc_p = ecma_make_empty_property_descriptor ();
#if JERRY_BUILTIN_PROXY
if (ECMA_OBJECT_IS_PROXY (object_p))
{
return ecma_proxy_object_get_own_property_descriptor (object_p, property_name_p, prop_desc_p);
}
#endif /* JERRY_BUILTIN_PROXY */
ecma_property_ref_t property_ref;
property_ref.virtual_value = ECMA_VALUE_EMPTY;
ecma_property_t property =
ecma_op_object_get_own_property (object_p, property_name_p, &property_ref, ECMA_PROPERTY_GET_VALUE);
if (!ECMA_PROPERTY_IS_FOUND (property))
{
#if JERRY_BUILTIN_TYPEDARRAY
if (JERRY_UNLIKELY (property == ECMA_PROPERTY_TYPE_NOT_FOUND_AND_THROW))
{
return ECMA_VALUE_ERROR;
}
#endif /* JERRY_BUILTIN_TYPEDARRAY */
JERRY_ASSERT (property == ECMA_PROPERTY_TYPE_NOT_FOUND || property == ECMA_PROPERTY_TYPE_NOT_FOUND_AND_STOP);
return ECMA_VALUE_FALSE;
}
uint32_t flags = ecma_is_property_enumerable (property) ? JERRY_PROP_IS_ENUMERABLE : JERRY_PROP_NO_OPTS;
flags |= ecma_is_property_configurable (property) ? JERRY_PROP_IS_CONFIGURABLE : JERRY_PROP_NO_OPTS;
prop_desc_p->flags = (uint16_t) (JERRY_PROP_IS_ENUMERABLE_DEFINED | JERRY_PROP_IS_CONFIGURABLE_DEFINED | flags);
if (property & ECMA_PROPERTY_FLAG_DATA)
{
if (!ECMA_PROPERTY_IS_VIRTUAL (property))
{
prop_desc_p->value = ecma_copy_value (property_ref.value_p->value);
}
else
{
#if JERRY_MODULE_SYSTEM
if (JERRY_UNLIKELY (property_ref.virtual_value == ECMA_VALUE_UNINITIALIZED))
{
return ecma_raise_reference_error (ECMA_ERR_LET_CONST_NOT_INITIALIZED);
}
#endif /* JERRY_MODULE_SYSTEM */
prop_desc_p->value = property_ref.virtual_value;
}
prop_desc_p->flags |= (JERRY_PROP_IS_VALUE_DEFINED | JERRY_PROP_IS_WRITABLE_DEFINED);
prop_desc_p->flags = (uint16_t) (
prop_desc_p->flags | (ecma_is_property_writable (property) ? JERRY_PROP_IS_WRITABLE : JERRY_PROP_NO_OPTS));
}
else
{
ecma_getter_setter_pointers_t *get_set_pair_p = ecma_get_named_accessor_property (property_ref.value_p);
prop_desc_p->flags |= (JERRY_PROP_IS_GET_DEFINED | JERRY_PROP_IS_SET_DEFINED);
if (get_set_pair_p->getter_cp == JMEM_CP_NULL)
{
prop_desc_p->get_p = NULL;
}
else
{
prop_desc_p->get_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, get_set_pair_p->getter_cp);
ecma_ref_object (prop_desc_p->get_p);
}
if (get_set_pair_p->setter_cp == JMEM_CP_NULL)
{
prop_desc_p->set_p = NULL;
}
else
{
prop_desc_p->set_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, get_set_pair_p->setter_cp);
ecma_ref_object (prop_desc_p->set_p);
}
}
return ECMA_VALUE_TRUE;
} /* ecma_op_object_get_own_property_descriptor */
#if JERRY_BUILTIN_PROXY
/**
* Get property descriptor from a target value for a specified property.
*
* For more details see ecma_op_object_get_own_property_descriptor
*
* @return ECMA_VALUE_ERROR - if the Proxy.[[GetOwnProperty]] operation raises error
* ECMA_VALUE_{TRUE, FALSE} - if property found or not
*/
ecma_value_t
ecma_op_get_own_property_descriptor (ecma_value_t target, /**< target value */
ecma_string_t *property_name_p, /**< property name */
ecma_property_descriptor_t *prop_desc_p) /**< property descriptor */
{
if (!ecma_is_value_object (target))
{
return ECMA_VALUE_FALSE;
}
return ecma_op_object_get_own_property_descriptor (ecma_get_object_from_value (target), property_name_p, prop_desc_p);
} /* ecma_op_get_own_property_descriptor */
#endif /* JERRY_BUILTIN_PROXY */
/**
* [[HasInstance]] ecma object's operation
*
* See also:
* ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 9
*
* @return ecma value containing a boolean value or an error
* Returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_op_object_has_instance (ecma_object_t *obj_p, /**< the object */
ecma_value_t value) /**< argument 'V' */
{
JERRY_ASSERT (obj_p != NULL && !ecma_is_lexical_environment (obj_p));
JERRY_ASSERT_OBJECT_TYPE_IS_VALID (ecma_get_object_type (obj_p));
if (ecma_op_object_is_callable (obj_p))
{
return ecma_op_function_has_instance (obj_p, value);
}
return ecma_raise_type_error (ECMA_ERR_EXPECTED_A_FUNCTION_OBJECT);
} /* ecma_op_object_has_instance */
/**
* General [[GetPrototypeOf]] abstract operation
*
* Note: returned valid object must be freed.
*
* @return ecma_object_t * - prototype of the input object.
* ECMA_OBJECT_POINTER_ERROR - error reported during Proxy resolve.
* NULL - the input object does not have a prototype.
*/
ecma_object_t *
ecma_op_object_get_prototype_of (ecma_object_t *obj_p) /**< input object */
{
JERRY_ASSERT (obj_p != NULL);
#if JERRY_BUILTIN_PROXY
if (ECMA_OBJECT_IS_PROXY (obj_p))
{
ecma_value_t proto = ecma_proxy_object_get_prototype_of (obj_p);
if (ECMA_IS_VALUE_ERROR (proto))
{
return ECMA_OBJECT_POINTER_ERROR;
}
if (ecma_is_value_null (proto))
{
return NULL;
}
JERRY_ASSERT (ecma_is_value_object (proto));
return ecma_get_object_from_value (proto);
}
else
#endif /* JERRY_BUILTIN_PROXY */
{
jmem_cpointer_t proto_cp = ecma_op_ordinary_object_get_prototype_of (obj_p);
if (proto_cp == JMEM_CP_NULL)
{
return NULL;
}
ecma_object_t *proto_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp);
ecma_ref_object (proto_p);
return proto_p;
}
} /* ecma_op_object_get_prototype_of */
/**
* Object's isPrototypeOf operation
*
* See also:
* ECMA-262 v5, 15.2.4.6; 3
*
* @return ECMA_VALUE_ERROR - if the operation fails
* ECMA_VALUE_TRUE - if the target object is prototype of the base object
* ECMA_VALUE_FALSE - if the target object is not prototype of the base object
*/
ecma_value_t
ecma_op_object_is_prototype_of (ecma_object_t *base_p, /**< base object */
ecma_object_t *target_p) /**< target object */
{
ecma_ref_object (target_p);
do
{
ecma_object_t *proto_p = ecma_op_object_get_prototype_of (target_p);
ecma_deref_object (target_p);
if (proto_p == NULL)
{
return ECMA_VALUE_FALSE;
}
else if (proto_p == ECMA_OBJECT_POINTER_ERROR)
{
return ECMA_VALUE_ERROR;
}
else if (proto_p == base_p)
{
ecma_deref_object (proto_p);
return ECMA_VALUE_TRUE;
}
/* Advance up on prototype chain. */
target_p = proto_p;
} while (true);
} /* ecma_op_object_is_prototype_of */
/**
* Object's EnumerableOwnPropertyNames operation
*
* See also:
* ECMA-262 v11, 7.3.23
*
* @return NULL - if operation fails
* collection of property names / values / name-value pairs - otherwise
*/
ecma_collection_t *
ecma_op_object_get_enumerable_property_names (ecma_object_t *obj_p, /**< routine's first argument */
ecma_enumerable_property_names_options_t option) /**< listing option */
{
/* 2. */
ecma_collection_t *prop_names_p = ecma_op_object_own_property_keys (obj_p, JERRY_PROPERTY_FILTER_EXCLUDE_SYMBOLS);
#if JERRY_BUILTIN_PROXY
if (JERRY_UNLIKELY (prop_names_p == NULL))
{
return prop_names_p;
}
#endif /* JERRY_BUILTIN_PROXY */
ecma_value_t *names_buffer_p = prop_names_p->buffer_p;
/* 3. */
ecma_collection_t *properties_p = ecma_new_collection ();
/* 4. */
for (uint32_t i = 0; i < prop_names_p->item_count; i++)
{
/* 4.a */
if (ecma_is_value_string (names_buffer_p[i]))
{
ecma_string_t *key_p = ecma_get_string_from_value (names_buffer_p[i]);
/* 4.a.i */
ecma_property_descriptor_t prop_desc;
ecma_value_t status = ecma_op_object_get_own_property_descriptor (obj_p, key_p, &prop_desc);
if (ECMA_IS_VALUE_ERROR (status))
{
ecma_collection_free (prop_names_p);
ecma_collection_free (properties_p);
return NULL;
}
const bool is_enumerable = (prop_desc.flags & JERRY_PROP_IS_ENUMERABLE) != 0;
ecma_free_property_descriptor (&prop_desc);
/* 4.a.ii */
if (is_enumerable)
{
/* 4.a.ii.1 */
if (option == ECMA_ENUMERABLE_PROPERTY_KEYS)
{
ecma_collection_push_back (properties_p, ecma_copy_value (names_buffer_p[i]));
}
else
{
/* 4.a.ii.2.a */
ecma_value_t value = ecma_op_object_get (obj_p, key_p);
if (ECMA_IS_VALUE_ERROR (value))
{
ecma_collection_free (prop_names_p);
ecma_collection_free (properties_p);
return NULL;
}
/* 4.a.ii.2.b */
if (option == ECMA_ENUMERABLE_PROPERTY_VALUES)
{
ecma_collection_push_back (properties_p, value);
}
else
{
/* 4.a.ii.2.c.i */
JERRY_ASSERT (option == ECMA_ENUMERABLE_PROPERTY_ENTRIES);
/* 4.a.ii.2.c.ii */
ecma_object_t *entry_p = ecma_op_new_array_object (2);
ecma_builtin_helper_def_prop_by_index (entry_p,
0,
names_buffer_p[i],
ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE);
ecma_builtin_helper_def_prop_by_index (entry_p, 1, value, ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE);
ecma_free_value (value);
/* 4.a.ii.2.c.iii */
ecma_collection_push_back (properties_p, ecma_make_object_value (entry_p));
}
}
}
}
}
ecma_collection_free (prop_names_p);
return properties_p;
} /* ecma_op_object_get_enumerable_property_names */
/**
* Helper method for getting lazy instantiated properties for [[OwnPropertyKeys]]
*/
static void
ecma_object_list_lazy_property_names (ecma_object_t *obj_p, /**< 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 */
{
switch (ecma_get_object_type (obj_p))
{
case ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION:
{
if (ecma_builtin_function_is_routine (obj_p))
{
ecma_builtin_routine_list_lazy_property_names (obj_p, prop_names_p, prop_counter_p, filter);
break;
}
/* FALLTHRU */
}
case ECMA_OBJECT_TYPE_BUILT_IN_GENERAL:
case ECMA_OBJECT_TYPE_BUILT_IN_CLASS:
case ECMA_OBJECT_TYPE_BUILT_IN_ARRAY:
{
ecma_builtin_list_lazy_property_names (obj_p, prop_names_p, prop_counter_p, filter);
break;
}
case ECMA_OBJECT_TYPE_CLASS:
{
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p;
switch (ext_object_p->u.cls.type)
{
case ECMA_OBJECT_CLASS_STRING:
{
ecma_op_string_list_lazy_property_names (obj_p, prop_names_p, prop_counter_p, filter);
break;
}
case ECMA_OBJECT_CLASS_ARGUMENTS:
{
ecma_op_arguments_object_list_lazy_property_names (obj_p, prop_names_p, prop_counter_p, filter);
break;
}
#if JERRY_BUILTIN_TYPEDARRAY
/* ES2015 9.4.5.1 */
case ECMA_OBJECT_CLASS_TYPEDARRAY:
{
ecma_op_typedarray_list_lazy_property_names (obj_p, prop_names_p, prop_counter_p, filter);
break;
}
#endif /* JERRY_BUILTIN_TYPEDARRAY */
}
break;
}
case ECMA_OBJECT_TYPE_FUNCTION:
{
ecma_op_function_list_lazy_property_names (obj_p, prop_names_p, prop_counter_p, filter);
break;
}
case ECMA_OBJECT_TYPE_NATIVE_FUNCTION:
{
ecma_op_external_function_list_lazy_property_names (obj_p, prop_names_p, prop_counter_p, filter);
break;
}
case ECMA_OBJECT_TYPE_BOUND_FUNCTION:
{
ecma_op_bound_function_list_lazy_property_names (obj_p, prop_names_p, prop_counter_p, filter);
break;
}
case ECMA_OBJECT_TYPE_ARRAY:
{
if (!(filter & JERRY_PROPERTY_FILTER_EXCLUDE_STRINGS))
{
ecma_collection_push_back (prop_names_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_LENGTH));
prop_counter_p->string_named_props++;
}
break;
}
default:
{
JERRY_ASSERT (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_GENERAL
|| ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_CONSTRUCTOR_FUNCTION);
break;
}
}
} /* ecma_object_list_lazy_property_names */
/**
* Helper routine for heapsort algorithm.
*/
static void
ecma_op_object_heap_sort_shift_down (ecma_value_t *buffer_p, /**< array of items */
uint32_t item_count, /**< number of items */
uint32_t item_index) /**< index of updated item */
{
while (true)
{
uint32_t highest_index = item_index;
uint32_t current_index = (item_index << 1) + 1;
if (current_index >= item_count)
{
return;
}
uint32_t value = ecma_string_get_array_index (ecma_get_string_from_value (buffer_p[highest_index]));
uint32_t left_value = ecma_string_get_array_index (ecma_get_string_from_value (buffer_p[current_index]));
if (value < left_value)
{
highest_index = current_index;
value = left_value;
}
current_index++;
if (current_index < item_count
&& value < ecma_string_get_array_index (ecma_get_string_from_value (buffer_p[current_index])))
{
highest_index = current_index;
}
if (highest_index == item_index)
{
return;
}
ecma_value_t tmp = buffer_p[highest_index];
buffer_p[highest_index] = buffer_p[item_index];
buffer_p[item_index] = tmp;
item_index = highest_index;
}
} /* ecma_op_object_heap_sort_shift_down */
/**
* Object's [[OwnPropertyKeys]] internal method
*
* Order of names in the collection:
* - integer indices in ascending order
* - other indices in creation order (for built-ins: the order of the properties are listed in specification).
*
* Note:
* Implementation of the routine assumes that new properties are appended to beginning of corresponding object's
* property list, and the list is not reordered (in other words, properties are stored in order that is reversed
* to the properties' addition order).
*
* @return NULL - if the Proxy.[[OwnPropertyKeys]] operation raises error
* collection of property names - otherwise
*/
ecma_collection_t *
ecma_op_object_own_property_keys (ecma_object_t *obj_p, /**< object */
jerry_property_filter_t filter) /**< name filters */
{
#if JERRY_BUILTIN_PROXY
if (ECMA_OBJECT_IS_PROXY (obj_p))
{
return ecma_proxy_object_own_property_keys (obj_p);
}
#endif /* JERRY_BUILTIN_PROXY */
if (ecma_op_object_is_fast_array (obj_p))
{
return ecma_fast_array_object_own_property_keys (obj_p, filter);
}
ecma_collection_t *prop_names_p = ecma_new_collection ();
ecma_property_counter_t prop_counter = { 0, 0, 0 };
ecma_object_list_lazy_property_names (obj_p, prop_names_p, &prop_counter, filter);
jmem_cpointer_t prop_iter_cp = obj_p->u1.property_list_cp;
#if JERRY_PROPERTY_HASHMAP
if (prop_iter_cp != JMEM_CP_NULL)
{
ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, prop_iter_cp);
if (prop_iter_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP)
{
prop_iter_cp = prop_iter_p->next_property_cp;
}
}
#endif /* JERRY_PROPERTY_HASHMAP */
jmem_cpointer_t counter_prop_iter_cp = prop_iter_cp;
uint32_t array_index_named_props = 0;
uint32_t string_named_props = 0;
uint32_t symbol_named_props = 0;
while (counter_prop_iter_cp != JMEM_CP_NULL)
{
ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, counter_prop_iter_cp);
JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));
for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++)
{
ecma_property_t *property_p = prop_iter_p->types + i;
if (!ECMA_PROPERTY_IS_RAW (*property_p) || (*property_p & ECMA_PROPERTY_FLAG_BUILT_IN))
{
continue;
}
ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p;
if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_DIRECT_STRING_MAGIC
&& prop_pair_p->names_cp[i] >= LIT_NON_INTERNAL_MAGIC_STRING__COUNT
&& prop_pair_p->names_cp[i] < LIT_MAGIC_STRING__COUNT)
{
continue;
}
ecma_string_t *name_p = ecma_string_from_property_name (*property_p, prop_pair_p->names_cp[i]);
if (ecma_string_get_array_index (name_p) != ECMA_STRING_NOT_ARRAY_INDEX)
{
array_index_named_props++;
}
else if (ecma_prop_name_is_symbol (name_p))
{
if (!(name_p->u.hash & ECMA_SYMBOL_FLAG_PRIVATE_KEY))
{
symbol_named_props++;
}
}
else
{
string_named_props++;
}
ecma_deref_ecma_string (name_p);
}
counter_prop_iter_cp = prop_iter_p->next_property_cp;
}
if (filter & JERRY_PROPERTY_FILTER_EXCLUDE_INTEGER_INDICES)
{
JERRY_ASSERT (prop_counter.array_index_named_props == 0);
array_index_named_props = 0;
}
if (filter & JERRY_PROPERTY_FILTER_EXCLUDE_STRINGS)
{
JERRY_ASSERT (prop_counter.string_named_props == 0);
string_named_props = 0;
}
if (filter & JERRY_PROPERTY_FILTER_EXCLUDE_SYMBOLS)
{
JERRY_ASSERT (prop_counter.symbol_named_props == 0);
symbol_named_props = 0;
}
uint32_t total = array_index_named_props + string_named_props + symbol_named_props;
if (total == 0)
{
return prop_names_p;
}
ecma_collection_reserve (prop_names_p, total);
prop_names_p->item_count += total;
ecma_value_t *buffer_p = prop_names_p->buffer_p;
ecma_value_t *array_index_current_p = buffer_p + array_index_named_props + prop_counter.array_index_named_props;
ecma_value_t *string_current_p = array_index_current_p + string_named_props + prop_counter.string_named_props;
ecma_value_t *symbol_current_p = string_current_p + symbol_named_props + prop_counter.symbol_named_props;
if (prop_counter.symbol_named_props > 0 && (array_index_named_props + string_named_props) > 0)
{
memmove ((void *) string_current_p,
(void *) (buffer_p + prop_counter.array_index_named_props + prop_counter.string_named_props),
prop_counter.symbol_named_props * sizeof (ecma_value_t));
}
if (prop_counter.string_named_props > 0 && array_index_named_props > 0)
{
memmove ((void *) array_index_current_p,
(void *) (buffer_p + prop_counter.array_index_named_props),
prop_counter.string_named_props * sizeof (ecma_value_t));
}
while (prop_iter_cp != JMEM_CP_NULL)
{
ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, prop_iter_cp);
JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));
for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++)
{
ecma_property_t *property_p = prop_iter_p->types + i;
if (!ECMA_PROPERTY_IS_RAW (*property_p) || (*property_p & ECMA_PROPERTY_FLAG_BUILT_IN))
{
continue;
}
ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p;
if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_DIRECT_STRING_MAGIC
&& prop_pair_p->names_cp[i] >= LIT_NON_INTERNAL_MAGIC_STRING__COUNT
&& prop_pair_p->names_cp[i] < LIT_MAGIC_STRING__COUNT)
{
continue;
}
ecma_string_t *name_p = ecma_string_from_property_name (*property_p, prop_pair_p->names_cp[i]);
if (ecma_string_get_array_index (name_p) != ECMA_STRING_NOT_ARRAY_INDEX)
{
if (!(filter & JERRY_PROPERTY_FILTER_EXCLUDE_INTEGER_INDICES))
{
*(--array_index_current_p) = ecma_make_string_value (name_p);
continue;
}
}
else if (ecma_prop_name_is_symbol (name_p))
{
if (!(filter & JERRY_PROPERTY_FILTER_EXCLUDE_SYMBOLS) && !(name_p->u.hash & ECMA_SYMBOL_FLAG_PRIVATE_KEY))
{
*(--symbol_current_p) = ecma_make_symbol_value (name_p);
continue;
}
}
else
{
if (!(filter & JERRY_PROPERTY_FILTER_EXCLUDE_STRINGS))
{
*(--string_current_p) = ecma_make_string_value (name_p);
continue;
}
}
ecma_deref_ecma_string (name_p);
}
prop_iter_cp = prop_iter_p->next_property_cp;
}
if (array_index_named_props > 1 || (array_index_named_props == 1 && prop_counter.array_index_named_props > 0))
{
uint32_t prev_value = 0;
ecma_value_t *array_index_p = buffer_p + prop_counter.array_index_named_props;
ecma_value_t *array_index_end_p = array_index_p + array_index_named_props;
if (prop_counter.array_index_named_props > 0)
{
prev_value = ecma_string_get_array_index (ecma_get_string_from_value (array_index_p[-1]));
}
do
{
uint32_t value = ecma_string_get_array_index (ecma_get_string_from_value (*array_index_p++));
if (value < prev_value)
{
uint32_t array_props = prop_counter.array_index_named_props + array_index_named_props;
uint32_t i = (array_props >> 1) - 1;
do
{
ecma_op_object_heap_sort_shift_down (buffer_p, array_props, i);
} while (i-- > 0);
i = array_props - 1;
do
{
ecma_value_t tmp = buffer_p[i];
buffer_p[i] = buffer_p[0];
buffer_p[0] = tmp;
ecma_op_object_heap_sort_shift_down (buffer_p, i, 0);
} while (--i > 0);
break;
}
prev_value = value;
} while (array_index_p < array_index_end_p);
}
return prop_names_p;
} /* ecma_op_object_own_property_keys */
/**
* EnumerateObjectProperties abstract method
*
* See also:
* ECMA-262 v11, 13.7.5.15
*
* @return NULL - if the Proxy.[[OwnPropertyKeys]] operation raises error
* collection of enumerable property names - otherwise
*/
ecma_collection_t *
ecma_op_object_enumerate (ecma_object_t *obj_p) /**< object */
{
ecma_collection_t *visited_names_p = ecma_new_collection ();
ecma_collection_t *return_names_p = ecma_new_collection ();
ecma_ref_object (obj_p);
while (true)
{
ecma_collection_t *keys = ecma_op_object_own_property_keys (obj_p, JERRY_PROPERTY_FILTER_EXCLUDE_SYMBOLS);
if (JERRY_UNLIKELY (keys == NULL))
{
ecma_collection_free (return_names_p);
ecma_collection_free (visited_names_p);
ecma_deref_object (obj_p);
return keys;
}
for (uint32_t i = 0; i < keys->item_count; i++)
{
ecma_value_t prop_name = keys->buffer_p[i];
ecma_string_t *name_p = ecma_get_prop_name_from_value (prop_name);
if (ecma_prop_name_is_symbol (name_p))
{
continue;
}
ecma_property_descriptor_t prop_desc;
ecma_value_t get_desc = ecma_op_object_get_own_property_descriptor (obj_p, name_p, &prop_desc);
if (ECMA_IS_VALUE_ERROR (get_desc))
{
ecma_collection_free (keys);
ecma_collection_free (return_names_p);
ecma_collection_free (visited_names_p);
ecma_deref_object (obj_p);
return NULL;
}
if (ecma_is_value_true (get_desc))
{
bool is_enumerable = (prop_desc.flags & JERRY_PROP_IS_ENUMERABLE) != 0;
ecma_free_property_descriptor (&prop_desc);
if (ecma_collection_has_string_value (visited_names_p, name_p)
|| ecma_collection_has_string_value (return_names_p, name_p))
{
continue;
}
ecma_ref_ecma_string (name_p);
if (is_enumerable)
{
ecma_collection_push_back (return_names_p, prop_name);
}
else
{
ecma_collection_push_back (visited_names_p, prop_name);
}
}
}
ecma_collection_free (keys);
/* Query the prototype. */
ecma_object_t *proto_p = ecma_op_object_get_prototype_of (obj_p);
ecma_deref_object (obj_p);
if (proto_p == NULL)
{
break;
}
else if (JERRY_UNLIKELY (proto_p == ECMA_OBJECT_POINTER_ERROR))
{
ecma_collection_free (return_names_p);
ecma_collection_free (visited_names_p);
return NULL;
}
/* Advance up on prototype chain. */
obj_p = proto_p;
}
ecma_collection_free (visited_names_p);
return return_names_p;
} /* ecma_op_object_enumerate */
#ifndef JERRY_NDEBUG
/**
* Check if passed object is the instance of specified built-in.
*
* @return true - if the object is instance of the specified built-in
* false - otherwise
*/
static bool
ecma_builtin_is (ecma_object_t *object_p, /**< pointer to an object */
ecma_builtin_id_t builtin_id) /**< id of built-in to check on */
{
JERRY_ASSERT (object_p != NULL && !ecma_is_lexical_environment (object_p));
JERRY_ASSERT (builtin_id < ECMA_BUILTIN_ID__COUNT);
ecma_object_type_t type = ecma_get_object_type (object_p);
switch (type)
{
case ECMA_OBJECT_TYPE_BUILT_IN_GENERAL:
case ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION:
{
ecma_extended_object_t *built_in_object_p = (ecma_extended_object_t *) object_p;
return (built_in_object_p->u.built_in.id == builtin_id && built_in_object_p->u.built_in.routine_id == 0);
}
case ECMA_OBJECT_TYPE_BUILT_IN_CLASS:
case ECMA_OBJECT_TYPE_BUILT_IN_ARRAY:
{
ecma_extended_built_in_object_t *extended_built_in_object_p = (ecma_extended_built_in_object_t *) object_p;
return (extended_built_in_object_p->built_in.id == builtin_id
&& extended_built_in_object_p->built_in.routine_id == 0);
}
default:
{
return false;
}
}
} /* ecma_builtin_is */
#endif /* !JERRY_NDEBUG */
/**
* The function is used in the assert of ecma_object_get_class_name
*
* @return true - if class name is an object
* false - otherwise
*/
static inline bool
ecma_object_check_class_name_is_object (ecma_object_t *obj_p) /**< object */
{
#ifndef JERRY_NDEBUG
return (ecma_builtin_is_global (obj_p)
#if JERRY_BUILTIN_TYPEDARRAY
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_ARRAYBUFFER_PROTOTYPE)
#if JERRY_BUILTIN_SHAREDARRAYBUFFER
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_SHARED_ARRAYBUFFER_PROTOTYPE)
#endif /* JERRY_BUILTIN_SHAREDARRAYBUFFER */
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_TYPEDARRAY_PROTOTYPE)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_INT8ARRAY_PROTOTYPE)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_UINT8ARRAY_PROTOTYPE)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_INT16ARRAY_PROTOTYPE)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_UINT16ARRAY_PROTOTYPE)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_INT32ARRAY_PROTOTYPE)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_UINT32ARRAY_PROTOTYPE)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_FLOAT32ARRAY_PROTOTYPE)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_UINT8CLAMPEDARRAY_PROTOTYPE)
#if JERRY_NUMBER_TYPE_FLOAT64
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_FLOAT64ARRAY_PROTOTYPE)
#endif /* JERRY_NUMBER_TYPE_FLOAT64 */
#if JERRY_BUILTIN_BIGINT
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_BIGINT_PROTOTYPE)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_BIGINT64ARRAY_PROTOTYPE)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_BIGUINT64ARRAY_PROTOTYPE)
#endif /* JERRY_BUILTIN_BIGINT */
#endif /* JERRY_BUILTIN_TYPEDARRAY */
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_ARRAY_PROTOTYPE_UNSCOPABLES)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_ARRAY_ITERATOR_PROTOTYPE)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_ITERATOR_PROTOTYPE)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_STRING_ITERATOR_PROTOTYPE)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_REGEXP_STRING_ITERATOR_PROTOTYPE)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_EVAL_ERROR_PROTOTYPE)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_RANGE_ERROR_PROTOTYPE)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_REFERENCE_ERROR_PROTOTYPE)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_SYNTAX_ERROR_PROTOTYPE)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_GENERATOR_PROTOTYPE)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_TYPE_ERROR_PROTOTYPE)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_AGGREGATE_ERROR_PROTOTYPE)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_URI_ERROR_PROTOTYPE)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_ERROR_PROTOTYPE)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_DATE_PROTOTYPE)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_REGEXP_PROTOTYPE)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_SYMBOL_PROTOTYPE)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_ASYNC_FUNCTION_PROTOTYPE)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_PROMISE_PROTOTYPE)
#if JERRY_BUILTIN_CONTAINER
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_MAP_PROTOTYPE)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_SET_PROTOTYPE)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_WEAKMAP_PROTOTYPE)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_WEAKSET_PROTOTYPE)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_MAP_ITERATOR_PROTOTYPE)
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_SET_ITERATOR_PROTOTYPE)
#endif /* JERRY_BUILTIN_CONTAINER */
#if JERRY_BUILTIN_WEAKREF
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_WEAKREF_PROTOTYPE)
#endif /* JERRY_BUILTIN_WEAKREF */
#if JERRY_BUILTIN_DATAVIEW
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_DATAVIEW_PROTOTYPE)
#endif /* JERRY_BUILTIN_DATAVIEW */
|| ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_OBJECT_PROTOTYPE));
#else /* JERRY_NDEBUG */
JERRY_UNUSED (obj_p);
return true;
#endif /* !JERRY_NDEBUG */
} /* ecma_object_check_class_name_is_object */
/**
* Used by ecma_object_get_class_name to get the magic string id of class objects
*/
static const uint16_t ecma_class_object_magic_string_id[] = {
/* These objects require custom property resolving. */
LIT_MAGIC_STRING_STRING_UL, /**< magic string id of ECMA_OBJECT_CLASS_STRING */
LIT_MAGIC_STRING_ARGUMENTS_UL, /**< magic string id of ECMA_OBJECT_CLASS_ARGUMENTS */
#if JERRY_BUILTIN_TYPEDARRAY
LIT_MAGIC_STRING__EMPTY, /**< ECMA_OBJECT_CLASS_TYPEDARRAY needs special resolver */
#endif /* JERRY_BUILTIN_TYPEDARRAY */
#if JERRY_MODULE_SYSTEM
LIT_MAGIC_STRING_MODULE_UL, /**< magic string id of ECMA_OBJECT_CLASS_MODULE_NAMESPACE */
#endif /* JERRY_MODULE_SYSTEM */
/* These objects are marked by Garbage Collector. */
LIT_MAGIC_STRING_GENERATOR_UL, /**< magic string id of ECMA_OBJECT_CLASS_GENERATOR */
LIT_MAGIC_STRING_ASYNC_GENERATOR_UL, /**< magic string id of ECMA_OBJECT_CLASS_ASYNC_GENERATOR */
LIT_MAGIC_STRING_ARRAY_ITERATOR_UL, /**< magic string id of ECMA_OBJECT_CLASS_ARRAY_ITERATOR */
LIT_MAGIC_STRING_SET_ITERATOR_UL, /**< magic string id of ECMA_OBJECT_CLASS_SET_ITERATOR */
LIT_MAGIC_STRING_MAP_ITERATOR_UL, /**< magic string id of ECMA_OBJECT_CLASS_MAP_ITERATOR */
#if JERRY_BUILTIN_REGEXP
LIT_MAGIC_STRING_REGEXP_STRING_ITERATOR_UL, /**< magic string id of ECMA_OBJECT_CLASS_REGEXP_STRING_ITERATOR */
#endif /* JERRY_BUILTIN_REGEXP */
#if JERRY_MODULE_SYSTEM
LIT_MAGIC_STRING_MODULE_UL, /**< magic string id of ECMA_OBJECT_CLASS_MODULE */
#endif /* JERRY_MODULE_SYSTEM */
LIT_MAGIC_STRING_PROMISE_UL, /**< magic string id of ECMA_OBJECT_CLASS_PROMISE */
LIT_MAGIC_STRING_OBJECT_UL, /**< magic string id of ECMA_OBJECT_CLASS_PROMISE_CAPABILITY */
LIT_MAGIC_STRING_OBJECT_UL, /**< magic string id of ECMA_OBJECT_CLASS_ASYNC_FROM_SYNC_ITERATOR */
#if JERRY_BUILTIN_DATAVIEW
LIT_MAGIC_STRING_DATAVIEW_UL, /**< magic string id of ECMA_OBJECT_CLASS_DATAVIEW */
#endif /* JERRY_BUILTIN_DATAVIEW */
#if JERRY_BUILTIN_CONTAINER
LIT_MAGIC_STRING__EMPTY, /**< magic string id of ECMA_OBJECT_CLASS_CONTAINER needs special resolver */
#endif /* JERRY_BUILTIN_CONTAINER */
/* Normal objects. */
LIT_MAGIC_STRING_BOOLEAN_UL, /**< magic string id of ECMA_OBJECT_CLASS_BOOLEAN */
LIT_MAGIC_STRING_NUMBER_UL, /**< magic string id of ECMA_OBJECT_CLASS_NUMBER */
LIT_MAGIC_STRING_ERROR_UL, /**< magic string id of ECMA_OBJECT_CLASS_ERROR */
LIT_MAGIC_STRING_OBJECT_UL, /**< magic string id of ECMA_OBJECT_CLASS_INTERNAL_OBJECT */
#if JERRY_PARSER
LIT_MAGIC_STRING_SCRIPT_UL, /**< magic string id of ECMA_OBJECT_CLASS_SCRIPT */
#endif /* JERRY_PARSER */
#if JERRY_BUILTIN_DATE
LIT_MAGIC_STRING_DATE_UL, /**< magic string id of ECMA_OBJECT_CLASS_DATE */
#endif /* JERRY_BUILTIN_DATE */
#if JERRY_BUILTIN_REGEXP
LIT_MAGIC_STRING_REGEXP_UL, /**< magic string id of ECMA_OBJECT_CLASS_REGEXP */
#endif /* JERRY_BUILTIN_REGEXP */
LIT_MAGIC_STRING_SYMBOL_UL, /**< magic string id of ECMA_OBJECT_CLASS_SYMBOL */
LIT_MAGIC_STRING_STRING_ITERATOR_UL, /**< magic string id of ECMA_OBJECT_CLASS_STRING_ITERATOR */
#if JERRY_BUILTIN_TYPEDARRAY
LIT_MAGIC_STRING_ARRAY_BUFFER_UL, /**< magic string id of ECMA_OBJECT_CLASS_ARRAY_BUFFER */
#endif /* JERRY_BUILTIN_TYPEDARRAY */
#if JERRY_BUILTIN_SHAREDARRAYBUFFER
LIT_MAGIC_STRING_SHARED_ARRAY_BUFFER_UL, /**< magic string id of ECMA_OBJECT_CLASS_SHAREDARRAY_BUFFER */
#endif /* JERRY_BUILTIN_SHAREDARRAYBUFFER */
#if JERRY_BUILTIN_BIGINT
LIT_MAGIC_STRING_BIGINT_UL, /**< magic string id of ECMA_OBJECT_CLASS_BIGINT */
#endif /* JERRY_BUILTIN_BIGINT */
#if JERRY_BUILTIN_WEAKREF
LIT_MAGIC_STRING_WEAKREF_UL, /**< magic string id of ECMA_OBJECT_CLASS_WEAKREF */
#endif /* JERRY_BUILTIN_WEAKREF */
};
JERRY_STATIC_ASSERT (sizeof (ecma_class_object_magic_string_id) == ECMA_OBJECT_CLASS__MAX * sizeof (uint16_t),
ecma_class_object_magic_string_id_must_have_object_class_max_elements);
/**
* Get [[Class]] string of specified object
*
* @return class name magic string
*/
lit_magic_string_id_t
ecma_object_get_class_name (ecma_object_t *obj_p) /**< object */
{
ecma_object_type_t type = ecma_get_object_type (obj_p);
switch (type)
{
case ECMA_OBJECT_TYPE_ARRAY:
case ECMA_OBJECT_TYPE_BUILT_IN_ARRAY:
{
return LIT_MAGIC_STRING_ARRAY_UL;
}
case ECMA_OBJECT_TYPE_CLASS:
case ECMA_OBJECT_TYPE_BUILT_IN_CLASS:
{
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p;
switch (ext_object_p->u.cls.type)
{
#if JERRY_BUILTIN_TYPEDARRAY
case ECMA_OBJECT_CLASS_TYPEDARRAY:
{
return ecma_get_typedarray_magic_string_id (ext_object_p->u.cls.u1.typedarray_type);
}
#endif /* JERRY_BUILTIN_TYPEDARRAY */
#if JERRY_BUILTIN_CONTAINER
case ECMA_OBJECT_CLASS_CONTAINER:
{
return (lit_magic_string_id_t) ext_object_p->u.cls.u2.container_id;
}
#endif /* JERRY_BUILTIN_CONTAINER */
default:
{
break;
}
}
JERRY_ASSERT (ext_object_p->u.cls.type < ECMA_OBJECT_CLASS__MAX);
JERRY_ASSERT (ecma_class_object_magic_string_id[ext_object_p->u.cls.type] != LIT_MAGIC_STRING__EMPTY);
return (lit_magic_string_id_t) ecma_class_object_magic_string_id[ext_object_p->u.cls.type];
}
case ECMA_OBJECT_TYPE_FUNCTION:
case ECMA_OBJECT_TYPE_NATIVE_FUNCTION:
case ECMA_OBJECT_TYPE_BOUND_FUNCTION:
case ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION:
case ECMA_OBJECT_TYPE_CONSTRUCTOR_FUNCTION:
{
return LIT_MAGIC_STRING_FUNCTION_UL;
}
#if JERRY_BUILTIN_PROXY
case ECMA_OBJECT_TYPE_PROXY:
{
ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) obj_p;
if (!ecma_is_value_null (proxy_obj_p->target) && ecma_is_value_object (proxy_obj_p->target))
{
ecma_object_t *target_obj_p = ecma_get_object_from_value (proxy_obj_p->target);
return ecma_object_get_class_name (target_obj_p);
}
return LIT_MAGIC_STRING_OBJECT_UL;
}
#endif /* JERRY_BUILTIN_PROXY */
case ECMA_OBJECT_TYPE_BUILT_IN_GENERAL:
{
ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p;
switch (ext_obj_p->u.built_in.id)
{
#if JERRY_BUILTIN_MATH
case ECMA_BUILTIN_ID_MATH:
{
return LIT_MAGIC_STRING_MATH_UL;
}
#endif /* JERRY_BUILTIN_MATH */
#if JERRY_BUILTIN_REFLECT
case ECMA_BUILTIN_ID_REFLECT:
{
return LIT_MAGIC_STRING_REFLECT_UL;
}
#endif /* JERRY_BUILTIN_REFLECT */
case ECMA_BUILTIN_ID_GENERATOR:
{
return LIT_MAGIC_STRING_GENERATOR_UL;
}
case ECMA_BUILTIN_ID_ASYNC_GENERATOR:
{
return LIT_MAGIC_STRING_ASYNC_GENERATOR_UL;
}
#if JERRY_BUILTIN_JSON
case ECMA_BUILTIN_ID_JSON:
{
return LIT_MAGIC_STRING_JSON_U;
}
#endif /* JERRY_BUILTIN_JSON */
#if JERRY_BUILTIN_ATOMICS
case ECMA_BUILTIN_ID_ATOMICS:
{
return LIT_MAGIC_STRING_ATOMICS_U;
}
#endif /* JERRY_BUILTIN_ATOMICS */
default:
{
break;
}
}
JERRY_ASSERT (ecma_object_check_class_name_is_object (obj_p));
return LIT_MAGIC_STRING_OBJECT_UL;
}
default:
{
JERRY_ASSERT (type == ECMA_OBJECT_TYPE_GENERAL || type == ECMA_OBJECT_TYPE_PROXY);
return LIT_MAGIC_STRING_OBJECT_UL;
}
}
} /* ecma_object_get_class_name */
#if JERRY_BUILTIN_REGEXP
/**
* Checks if the given argument has [[RegExpMatcher]] internal slot
*
* @return true - if the given argument is a regexp
* false - otherwise
*/
extern inline bool JERRY_ATTR_ALWAYS_INLINE
ecma_object_is_regexp_object (ecma_value_t arg) /**< argument */
{
return (ecma_is_value_object (arg)
&& ecma_object_class_is (ecma_get_object_from_value (arg), ECMA_OBJECT_CLASS_REGEXP));
} /* ecma_object_is_regexp_object */
#endif /* JERRY_BUILTIN_REGEXP */
/**
* Object's IsConcatSpreadable operation, used for Array.prototype.concat
* It checks the argument's [Symbol.isConcatSpreadable] property value
*
* See also:
* ECMA-262 v6, 22.1.3.1.1;
*
* @return ECMA_VALUE_ERROR - if the operation fails
* ECMA_VALUE_TRUE - if the argument is concatSpreadable
* ECMA_VALUE_FALSE - otherwise
*/
ecma_value_t
ecma_op_is_concat_spreadable (ecma_value_t arg) /**< argument */
{
if (!ecma_is_value_object (arg))
{
return ECMA_VALUE_FALSE;
}
ecma_value_t spreadable =
ecma_op_object_get_by_symbol_id (ecma_get_object_from_value (arg), LIT_GLOBAL_SYMBOL_IS_CONCAT_SPREADABLE);
if (ECMA_IS_VALUE_ERROR (spreadable))
{
return spreadable;
}
if (!ecma_is_value_undefined (spreadable))
{
const bool to_bool = ecma_op_to_boolean (spreadable);
ecma_free_value (spreadable);
return ecma_make_boolean_value (to_bool);
}
return ecma_is_value_array (arg);
} /* ecma_op_is_concat_spreadable */
/**
* IsRegExp operation
*
* See also:
* ECMA-262 v6, 22.1.3.1.1;
*
* @return ECMA_VALUE_ERROR - if the operation fails
* ECMA_VALUE_TRUE - if the argument is regexp
* ECMA_VALUE_FALSE - otherwise
*/
ecma_value_t
ecma_op_is_regexp (ecma_value_t arg) /**< argument */
{
if (!ecma_is_value_object (arg))
{
return ECMA_VALUE_FALSE;
}
ecma_value_t is_regexp = ecma_op_object_get_by_symbol_id (ecma_get_object_from_value (arg), LIT_GLOBAL_SYMBOL_MATCH);
if (ECMA_IS_VALUE_ERROR (is_regexp))
{
return is_regexp;
}
if (!ecma_is_value_undefined (is_regexp))
{
const bool to_bool = ecma_op_to_boolean (is_regexp);
ecma_free_value (is_regexp);
return ecma_make_boolean_value (to_bool);
}
return ecma_make_boolean_value (ecma_object_is_regexp_object (arg));
} /* ecma_op_is_regexp */
/**
* SpeciesConstructor operation
* See also:
* ECMA-262 v6, 7.3.20;
*
* @return ecma_value
* returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_op_species_constructor (ecma_object_t *this_value, /**< This Value */
ecma_builtin_id_t default_constructor_id) /**< Builtin ID of default constructor */
{
ecma_object_t *default_constructor_p = ecma_builtin_get (default_constructor_id);
ecma_value_t constructor = ecma_op_object_get_by_magic_id (this_value, LIT_MAGIC_STRING_CONSTRUCTOR);
if (ECMA_IS_VALUE_ERROR (constructor))
{
return constructor;
}
if (ecma_is_value_undefined (constructor))
{
ecma_ref_object (default_constructor_p);
return ecma_make_object_value (default_constructor_p);
}
if (!ecma_is_value_object (constructor))
{
ecma_free_value (constructor);
return ecma_raise_type_error (ECMA_ERR_CONSTRUCTOR_NOT_AN_OBJECT);
}
ecma_object_t *ctor_object_p = ecma_get_object_from_value (constructor);
ecma_value_t species = ecma_op_object_get_by_symbol_id (ctor_object_p, LIT_GLOBAL_SYMBOL_SPECIES);
ecma_deref_object (ctor_object_p);
if (ECMA_IS_VALUE_ERROR (species))
{
return species;
}
if (ecma_is_value_undefined (species) || ecma_is_value_null (species))
{
ecma_ref_object (default_constructor_p);
return ecma_make_object_value (default_constructor_p);
}
if (!ecma_is_constructor (species))
{
ecma_free_value (species);
return ecma_raise_type_error (ECMA_ERR_SPECIES_MUST_BE_A_CONSTRUCTOR);
}
return species;
} /* ecma_op_species_constructor */
/**
* 7.3.18 Abstract operation Invoke when property name is a magic string
*
* @return ecma_value result of the invoked function or raised error
* note: returned value must be freed with ecma_free_value
*/
extern inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE
ecma_op_invoke_by_symbol_id (ecma_value_t object, /**< Object value */
lit_magic_string_id_t symbol_id, /**< Symbol ID */
ecma_value_t *args_p, /**< Argument list */
uint32_t args_len) /**< Argument list length */
{
ecma_string_t *symbol_p = ecma_op_get_global_symbol (symbol_id);
ecma_value_t ret_value = ecma_op_invoke (object, symbol_p, args_p, args_len);
ecma_deref_ecma_string (symbol_p);
return ret_value;
} /* ecma_op_invoke_by_symbol_id */
/**
* 7.3.18 Abstract operation Invoke when property name is a magic string
*
* @return ecma_value result of the invoked function or raised error
* note: returned value must be freed with ecma_free_value
*/
extern inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE
ecma_op_invoke_by_magic_id (ecma_value_t object, /**< Object value */
lit_magic_string_id_t magic_string_id, /**< Magic string ID */
ecma_value_t *args_p, /**< Argument list */
uint32_t args_len) /**< Argument list length */
{
return ecma_op_invoke (object, ecma_get_magic_string (magic_string_id), args_p, args_len);
} /* ecma_op_invoke_by_magic_id */
/**
* 7.3.18 Abstract operation Invoke
*
* @return ecma_value result of the invoked function or raised error
* note: returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_op_invoke (ecma_value_t object, /**< Object value */
ecma_string_t *property_name_p, /**< Property name */
ecma_value_t *args_p, /**< Argument list */
uint32_t args_len) /**< Argument list length */
{
/* 3. */
ecma_value_t object_value = ecma_op_to_object (object);
if (ECMA_IS_VALUE_ERROR (object_value))
{
return object_value;
}
ecma_object_t *object_p = ecma_get_object_from_value (object_value);
ecma_value_t func = ecma_op_object_get_with_receiver (object_p, property_name_p, object);
if (ECMA_IS_VALUE_ERROR (func))
{
ecma_deref_object (object_p);
return func;
}
/* 4. */
ecma_value_t call_result = ecma_op_function_validated_call (func, object, args_p, args_len);
ecma_free_value (func);
ecma_deref_object (object_p);
return call_result;
} /* ecma_op_invoke */
/**
* Ordinary object [[GetPrototypeOf]] operation
*
* See also:
* ECMAScript v6, 9.1.1
*
* @return the value of the [[Prototype]] internal slot of the given object.
*/
extern inline jmem_cpointer_t JERRY_ATTR_ALWAYS_INLINE
ecma_op_ordinary_object_get_prototype_of (ecma_object_t *obj_p) /**< object */
{
JERRY_ASSERT (!ecma_is_lexical_environment (obj_p));
JERRY_ASSERT (!ECMA_OBJECT_IS_PROXY (obj_p));
return obj_p->u2.prototype_cp;
} /* ecma_op_ordinary_object_get_prototype_of */
/**
* Ordinary object [[SetPrototypeOf]] operation
*
* See also:
* ECMAScript v6, 9.1.2
*
* @return ECMA_VALUE_FALSE - if the operation fails
* ECMA_VALUE_TRUE - otherwise
*/
extern inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE
ecma_op_ordinary_object_set_prototype_of (ecma_object_t *obj_p, /**< base object */
ecma_value_t proto) /**< prototype object */
{
JERRY_ASSERT (!ecma_is_lexical_environment (obj_p));
JERRY_ASSERT (!ECMA_OBJECT_IS_PROXY (obj_p));
/* 1. */
JERRY_ASSERT (ecma_is_value_object (proto) || ecma_is_value_null (proto));
/* 3. */
ecma_object_t *current_proto_p = ECMA_GET_POINTER (ecma_object_t, ecma_op_ordinary_object_get_prototype_of (obj_p));
ecma_object_t *new_proto_p = ecma_is_value_null (proto) ? NULL : ecma_get_object_from_value (proto);
/* 4. */
if (new_proto_p == current_proto_p)
{
return ECMA_VALUE_TRUE;
}
/* 2 - 5. */
if (!ecma_op_ordinary_object_is_extensible (obj_p))
{
return ECMA_VALUE_FALSE;
}
/**
* When the prototype of a fast array changes, it is required to convert the
* array to a "normal" array. This ensures that all [[Get]]/[[Set]]/etc.
* calls works as expected.
*/
if (ecma_op_object_is_fast_array (obj_p))
{
ecma_fast_array_convert_to_normal (obj_p);
}
/* 6. */
ecma_object_t *iter_p = new_proto_p;
/* 7 - 8. */
while (true)
{
/* 8.a */
if (iter_p == NULL)
{
break;
}
/* 8.b */
if (obj_p == iter_p)
{
return ECMA_VALUE_FALSE;
}
/* 8.c.i */
#if JERRY_BUILTIN_PROXY
if (ECMA_OBJECT_IS_PROXY (iter_p))
{
/**
* Prevent setting 'Object.prototype.__proto__'
* to avoid circular referencing in the prototype chain.
*/
if (obj_p == ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE))
{
return ECMA_VALUE_FALSE;
}
break;
}
#endif /* JERRY_BUILTIN_PROXY */
/* 8.c.ii */
iter_p = ECMA_GET_POINTER (ecma_object_t, ecma_op_ordinary_object_get_prototype_of (iter_p));
}
/* 9. */
ECMA_SET_POINTER (obj_p->u2.prototype_cp, new_proto_p);
/* 10. */
return ECMA_VALUE_TRUE;
} /* ecma_op_ordinary_object_set_prototype_of */
/**
* [[IsExtensible]] operation for Ordinary object.
*
* See also:
* ECMAScript v6, 9.1.2
*
* @return true - if object is extensible
* false - otherwise
*/
extern inline bool JERRY_ATTR_PURE
ecma_op_ordinary_object_is_extensible (ecma_object_t *object_p) /**< object */
{
JERRY_ASSERT (!ECMA_OBJECT_IS_PROXY (object_p));
bool is_extensible = (object_p->type_flags_refs & ECMA_OBJECT_FLAG_EXTENSIBLE) != 0;
JERRY_ASSERT (!ecma_op_object_is_fast_array (object_p) || is_extensible);
return is_extensible;
} /* ecma_op_ordinary_object_is_extensible */
/**
* Set value of [[Extensible]] object's internal property.
*
* @return void
*/
void JERRY_ATTR_NOINLINE
ecma_op_ordinary_object_prevent_extensions (ecma_object_t *object_p) /**< object */
{
JERRY_ASSERT (!ECMA_OBJECT_IS_PROXY (object_p));
if (JERRY_UNLIKELY (ecma_op_object_is_fast_array (object_p)))
{
ecma_fast_array_convert_to_normal (object_p);
}
object_p->type_flags_refs &= (ecma_object_descriptor_t) ~ECMA_OBJECT_FLAG_EXTENSIBLE;
} /* ecma_op_ordinary_object_prevent_extensions */
/**
* Checks whether an object (excluding prototypes) has a named property
*
* @return true - if property is found
* false - otherwise
*/
extern inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE
ecma_op_ordinary_object_has_own_property (ecma_object_t *object_p, /**< the object */
ecma_string_t *property_name_p) /**< property name */
{
JERRY_ASSERT (!ECMA_OBJECT_IS_PROXY (object_p));
ecma_property_t property =
ecma_op_object_get_own_property (object_p, property_name_p, NULL, ECMA_PROPERTY_GET_NO_OPTIONS);
#if JERRY_BUILTIN_TYPEDARRAY
if (JERRY_UNLIKELY (property == ECMA_PROPERTY_TYPE_NOT_FOUND_AND_THROW))
{
return ECMA_VALUE_ERROR;
}
#endif /* JERRY_BUILTIN_TYPEDARRAY */
JERRY_ASSERT (ECMA_PROPERTY_IS_FOUND (property) || property == ECMA_PROPERTY_TYPE_NOT_FOUND
|| property == ECMA_PROPERTY_TYPE_NOT_FOUND_AND_STOP);
return ecma_make_boolean_value (ECMA_PROPERTY_IS_FOUND (property));
} /* ecma_op_ordinary_object_has_own_property */
/**
* Checks whether an object (excluding prototypes) has a named property. Handles proxy objects too.
*
* @return true - if property is found
* false - otherwise
*/
ecma_value_t
ecma_op_object_has_own_property (ecma_object_t *object_p, /**< the object */
ecma_string_t *property_name_p) /**< property name */
{
#if JERRY_BUILTIN_PROXY
if (ECMA_OBJECT_IS_PROXY (object_p))
{
ecma_property_descriptor_t prop_desc;
ecma_value_t status = ecma_proxy_object_get_own_property_descriptor (object_p, property_name_p, &prop_desc);
if (ecma_is_value_true (status))
{
ecma_free_property_descriptor (&prop_desc);
}
return status;
}
#endif /* JERRY_BUILTIN_PROXY */
return ecma_op_ordinary_object_has_own_property (object_p, property_name_p);
} /* ecma_op_object_has_own_property */
#if JERRY_BUILTIN_WEAKREF || JERRY_BUILTIN_CONTAINER
/**
* Set a weak reference from a container or WeakRefObject to a key object
*/
void
ecma_op_object_set_weak (ecma_object_t *object_p, /**< key object */
ecma_object_t *target_p) /**< target object */
{
if (JERRY_UNLIKELY (ecma_op_object_is_fast_array (object_p)))
{
ecma_fast_array_convert_to_normal (object_p);
}
ecma_string_t *weak_refs_string_p = ecma_get_internal_string (LIT_INTERNAL_MAGIC_STRING_WEAK_REFS);
ecma_property_t *property_p = ecma_find_named_property (object_p, weak_refs_string_p);
ecma_collection_t *refs_p;
if (property_p == NULL)
{
refs_p = ecma_new_collection ();
ecma_property_value_t *value_p;
ECMA_CREATE_INTERNAL_PROPERTY (object_p, weak_refs_string_p, property_p, value_p);
ECMA_SET_INTERNAL_VALUE_POINTER (value_p->value, refs_p);
}
else
{
refs_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, (ECMA_PROPERTY_VALUE_PTR (property_p)->value));
}
const ecma_value_t target_value = ecma_make_object_value ((ecma_object_t *) target_p);
for (uint32_t i = 0; i < refs_p->item_count; i++)
{
if (ecma_is_value_empty (refs_p->buffer_p[i]))
{
refs_p->buffer_p[i] = target_value;
return;
}
}
ecma_collection_push_back (refs_p, target_value);
} /* ecma_op_object_set_weak */
/**
* Helper function to remove a weak reference to an object.
*
* @return ecma value
* Returned value must be freed with ecma_free_value.
*/
void
ecma_op_object_unref_weak (ecma_object_t *object_p, /**< this argument */
ecma_value_t ref_holder) /**< key argument */
{
ecma_string_t *weak_refs_string_p = ecma_get_internal_string (LIT_INTERNAL_MAGIC_STRING_WEAK_REFS);
ecma_property_t *property_p = ecma_find_named_property (object_p, weak_refs_string_p);
JERRY_ASSERT (property_p != NULL);
ecma_collection_t *refs_p =
ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, ECMA_PROPERTY_VALUE_PTR (property_p)->value);
ecma_value_t *buffer_p = refs_p->buffer_p;
while (true)
{
if (*buffer_p == ref_holder)
{
*buffer_p = ECMA_VALUE_EMPTY;
return;
}
JERRY_ASSERT (buffer_p < refs_p->buffer_p + refs_p->item_count);
buffer_p++;
}
} /* ecma_op_object_unref_weak */
#endif /* JERRY_BUILTIN_WEAKREF || JERRY_BUILTIN_CONTAINER */
/**
* Raise property redefinition error
*
* @return ECMA_VALUE_FALSE - if JERRY_PROP_SHOULD_THROW is not set
* raised TypeError - otherwise
*/
ecma_value_t
ecma_raise_property_redefinition (ecma_string_t *property_name_p, /**< property name */
uint16_t flags) /**< property descriptor flags */
{
JERRY_UNUSED (property_name_p);
return ECMA_REJECT_WITH_FORMAT (flags & JERRY_PROP_SHOULD_THROW,
"Cannot redefine property: %",
ecma_make_prop_name_value (property_name_p));
} /* ecma_raise_property_redefinition */
/**
* Raise readonly assignment error
*
* @return ECMA_VALUE_FALSE - if is_throw is true
* raised TypeError - otherwise
*/
ecma_value_t
ecma_raise_readonly_assignment (ecma_string_t *property_name_p, /**< property name */
bool is_throw) /**< is throw flag */
{
JERRY_UNUSED (property_name_p);
return ECMA_REJECT_WITH_FORMAT (is_throw,
"Cannot assign to read only property '%'",
ecma_make_prop_name_value (property_name_p));
} /* ecma_raise_readonly_assignment */
/**
* @}
* @}
*/