/** * The Date.prototype object's 'toJSON' routine * * See also: * ECMA-262 v5, 15.9.5.44 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_date_prototype_to_json (ecma_value_t this_arg, /**< this argument */ ecma_value_t arg) /**< key */ { JERRY_UNUSED (arg); ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); /* 1. */ ECMA_TRY_CATCH (obj, ecma_op_to_object (this_arg), ret_value); /* 2. */ ECMA_TRY_CATCH (tv, ecma_op_to_primitive (obj, ECMA_PREFERRED_TYPE_NUMBER), ret_value); /* 3. */ if (ecma_is_value_number (tv)) { ecma_number_t num_value = ecma_get_number_from_value (tv); if (ecma_number_is_nan (num_value) || ecma_number_is_infinity (num_value)) { ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_NULL); } } if (ecma_is_value_empty (ret_value)) { ecma_string_t *to_iso_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_TO_ISO_STRING_UL); ecma_object_t *value_obj_p = ecma_get_object_from_value (obj); /* 4. */ ECMA_TRY_CATCH (to_iso, ecma_op_object_get (value_obj_p, to_iso_str_p), ret_value); /* 5. */ if (!ecma_op_is_callable (to_iso)) { ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("")); } /* 6. */ else { ecma_object_t *to_iso_obj_p = ecma_get_object_from_value (to_iso); ret_value = ecma_op_function_call (to_iso_obj_p, this_arg, NULL, 0); } ECMA_FINALIZE (to_iso); ecma_deref_ecma_string (to_iso_str_p); } ECMA_FINALIZE (tv); ECMA_FINALIZE (obj); return ret_value; } /* ecma_builtin_date_prototype_to_json */
/** * ToObject operation. * * See also: * ECMA-262 v5, 9.9 * * @return ecma value * Returned value must be freed with ecma_free_value */ ecma_value_t ecma_op_to_object (ecma_value_t value) /**< ecma value */ { ecma_check_value_type_is_spec_defined (value); if (ecma_is_value_number (value)) { return ecma_op_create_number_object (value); } else if (ecma_is_value_string (value)) { return ecma_op_create_string_object (&value, 1); } else if (ecma_is_value_object (value)) { return ecma_copy_value (value); } else { if (ecma_is_value_undefined (value) || ecma_is_value_null (value)) { return ecma_raise_type_error (ECMA_ERR_MSG ("")); } else { JERRY_ASSERT (ecma_is_value_boolean (value)); return ecma_op_create_boolean_object (value); } } } /* ecma_op_to_object */
/** * ToObject operation. * * See also: * ECMA-262 v5, 9.9 * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t ecma_op_to_object (ecma_value_t value) /**< ecma-value */ { ecma_check_value_type_is_spec_defined (value); if (ecma_is_value_number (value)) { return ecma_op_create_number_object (value); } else if (ecma_is_value_string (value)) { return ecma_op_create_string_object (&value, 1); } else if (ecma_is_value_object (value)) { return ecma_make_normal_completion_value (ecma_copy_value (value, true)); } else { if (ecma_is_value_undefined (value) || ecma_is_value_null (value)) { return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } else { JERRY_ASSERT (ecma_is_value_boolean (value)); return ecma_op_create_boolean_object (value); } } } /* ecma_op_to_object */
/** * The Number.prototype object's 'valueOf' routine * * See also: * ECMA-262 v5, 15.7.4.4 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_number_prototype_object_value_of (ecma_value_t this_arg) /**< this argument */ { if (ecma_is_value_number (this_arg)) { return ecma_copy_value (this_arg); } else if (ecma_is_value_object (this_arg)) { ecma_object_t *obj_p = ecma_get_object_from_value (this_arg); if (ecma_object_get_class_name (obj_p) == LIT_MAGIC_STRING_NUMBER_UL) { ecma_property_t *prim_value_prop_p = ecma_get_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_PRIMITIVE_NUMBER_VALUE); ecma_number_t *prim_value_num_p; prim_value_num_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_number_t, ecma_get_internal_property_value (prim_value_prop_p)); ecma_number_t *ret_num_p = ecma_alloc_number (); *ret_num_p = *prim_value_num_p; return ecma_make_number_value (ret_num_p); } } return ecma_raise_type_error (ECMA_ERR_MSG ("")); } /* ecma_builtin_number_prototype_object_value_of */
/** * ToString operation. * * See also: * ECMA-262 v5, 9.8 * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t ecma_op_to_string (ecma_value_t value) /**< ecma-value */ { ecma_check_value_type_is_spec_defined (value); if (unlikely (ecma_is_value_object (value))) { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); ECMA_TRY_CATCH (prim_value, ecma_op_to_primitive (value, ECMA_PREFERRED_TYPE_STRING), ret_value); ret_value = ecma_op_to_string (prim_value); ECMA_FINALIZE (prim_value); return ret_value; } else { ecma_string_t *res_p = NULL; if (ecma_is_value_string (value)) { res_p = ecma_get_string_from_value (value); res_p = ecma_copy_or_ref_ecma_string (res_p); } else if (ecma_is_value_number (value)) { ecma_number_t *num_p = ecma_get_number_from_value (value); res_p = ecma_new_ecma_string_from_number (*num_p); } else if (ecma_is_value_undefined (value)) { res_p = ecma_get_magic_string (LIT_MAGIC_STRING_UNDEFINED); } else if (ecma_is_value_null (value)) { res_p = ecma_get_magic_string (LIT_MAGIC_STRING_NULL); } else { JERRY_ASSERT (ecma_is_value_boolean (value)); if (ecma_is_value_true (value)) { res_p = ecma_get_magic_string (LIT_MAGIC_STRING_TRUE); } else { res_p = ecma_get_magic_string (LIT_MAGIC_STRING_FALSE); } } return ecma_make_normal_completion_value (ecma_make_string_value (res_p)); } } /* ecma_op_to_string */
/** * Update getter or setter for object literals. */ void opfunc_set_accessor (bool is_getter, /**< is getter accessor */ ecma_value_t object, /**< object value */ ecma_value_t accessor_name, /**< accessor name value */ ecma_value_t accessor) /**< accessor value */ { ecma_object_t *object_p = ecma_get_object_from_value (object); JERRY_ASSERT (ecma_is_value_string (accessor_name) || ecma_is_value_number (accessor_name)); ecma_string_t *accessor_name_p = ecma_get_string_from_value (ecma_op_to_string (accessor_name)); ecma_property_t *property_p = ecma_find_named_property (object_p, accessor_name_p); if (property_p != NULL && ECMA_PROPERTY_GET_TYPE (*property_p) != ECMA_PROPERTY_TYPE_NAMEDACCESSOR) { ecma_delete_property (object_p, ECMA_PROPERTY_VALUE_PTR (property_p)); property_p = NULL; } if (property_p == NULL) { ecma_object_t *getter_func_p = NULL; ecma_object_t *setter_func_p = NULL; if (is_getter) { getter_func_p = ecma_get_object_from_value (accessor); } else { setter_func_p = ecma_get_object_from_value (accessor); } ecma_create_named_accessor_property (object_p, accessor_name_p, getter_func_p, setter_func_p, ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE, NULL); } else if (is_getter) { ecma_object_t *getter_func_p = ecma_get_object_from_value (accessor); ecma_set_named_accessor_property_getter (object_p, ECMA_PROPERTY_VALUE_PTR (property_p), getter_func_p); } else { ecma_object_t *setter_func_p = ecma_get_object_from_value (accessor); ecma_set_named_accessor_property_setter (object_p, ECMA_PROPERTY_VALUE_PTR (property_p), setter_func_p); } ecma_deref_ecma_string (accessor_name_p); } /* opfunc_set_accessor */
/** * Debug assertion that specified value's type is one of ECMA-defined * script-visible types, i.e.: undefined, null, boolean, number, string, object. */ void ecma_check_value_type_is_spec_defined (ecma_value_t value) /**< ecma value */ { JERRY_ASSERT (ecma_is_value_undefined (value) || ecma_is_value_null (value) || ecma_is_value_boolean (value) || ecma_is_value_number (value) || ecma_is_value_string (value) || ecma_is_value_object (value)); } /* ecma_check_value_type_is_spec_defined */
/** * The Date.prototype object's 'toJSON' routine * * See also: * ECMA-262 v5, 15.9.5.44 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_date_prototype_to_json (ecma_value_t this_arg) /**< this argument */ { ecma_value_t ret_value = ECMA_VALUE_EMPTY; /* 1. */ ECMA_TRY_CATCH (obj, ecma_op_to_object (this_arg), ret_value); /* 2. */ ECMA_TRY_CATCH (tv, ecma_op_to_primitive (obj, ECMA_PREFERRED_TYPE_NUMBER), ret_value); /* 3. */ if (ecma_is_value_number (tv)) { ecma_number_t num_value = ecma_get_number_from_value (tv); if (ecma_number_is_nan (num_value) || ecma_number_is_infinity (num_value)) { ret_value = ECMA_VALUE_NULL; } } if (ecma_is_value_empty (ret_value)) { ecma_object_t *value_obj_p = ecma_get_object_from_value (obj); /* 4. */ ECMA_TRY_CATCH (to_iso, ecma_op_object_get_by_magic_id (value_obj_p, LIT_MAGIC_STRING_TO_ISO_STRING_UL), ret_value); /* 5. */ if (!ecma_op_is_callable (to_iso)) { ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("'toISOString' is missing or not a function.")); } /* 6. */ else { ecma_object_t *to_iso_obj_p = ecma_get_object_from_value (to_iso); ret_value = ecma_op_function_call (to_iso_obj_p, this_arg, NULL, 0); } ECMA_FINALIZE (to_iso); } ECMA_FINALIZE (tv); ECMA_FINALIZE (obj); return ret_value; } /* ecma_builtin_date_prototype_to_json */
/** * ToBoolean operation. * * See also: * ECMA-262 v5, 9.2 * * @return completion value * Returned value is simple and so need not be freed. * However, ecma_free_completion_value may be called for it, but it is a no-op. */ ecma_completion_value_t ecma_op_to_boolean (ecma_value_t value) /**< ecma-value */ { ecma_check_value_type_is_spec_defined (value); ecma_simple_value_t ret_value; if (ecma_is_value_boolean (value)) { ret_value = (ecma_is_value_true (value) ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE); } else if (ecma_is_value_undefined (value) || ecma_is_value_null (value)) { ret_value = ECMA_SIMPLE_VALUE_FALSE; } else if (ecma_is_value_number (value)) { ecma_number_t *num_p = ecma_get_number_from_value (value); if (ecma_number_is_nan (*num_p) || ecma_number_is_zero (*num_p)) { ret_value = ECMA_SIMPLE_VALUE_FALSE; } else { ret_value = ECMA_SIMPLE_VALUE_TRUE; } } else if (ecma_is_value_string (value)) { ecma_string_t *str_p = ecma_get_string_from_value (value); if (ecma_string_get_length (str_p) == 0) { ret_value = ECMA_SIMPLE_VALUE_FALSE; } else { ret_value = ECMA_SIMPLE_VALUE_TRUE; } } else { JERRY_ASSERT (ecma_is_value_object (value)); ret_value = ECMA_SIMPLE_VALUE_TRUE; } return ecma_make_simple_completion_value (ret_value); } /* ecma_op_to_boolean */
/** * The Number.prototype object's 'valueOf' routine * * See also: * ECMA-262 v5, 15.7.4.4 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_number_prototype_object_value_of (ecma_value_t this_arg) /**< this argument */ { if (ecma_is_value_number (this_arg)) { return ecma_copy_value (this_arg); } else if (ecma_is_value_object (this_arg)) { ecma_object_t *obj_p = ecma_get_object_from_value (this_arg); if (ecma_object_get_class_name (obj_p) == LIT_MAGIC_STRING_NUMBER_UL) { ecma_property_t *prim_value_prop_p = ecma_get_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_ECMA_VALUE); JERRY_ASSERT (ecma_is_value_number (ecma_get_internal_property_value (prim_value_prop_p))); return ecma_copy_value (ecma_get_internal_property_value (prim_value_prop_p)); } } return ecma_raise_type_error (ECMA_ERR_MSG ("")); } /* ecma_builtin_number_prototype_object_value_of */
/** * Assign value to named data property * * Note: * value previously stored in the property is freed */ void ecma_named_data_property_assign_value (ecma_object_t *obj_p, /**< object */ ecma_property_t *prop_p, /**< property */ ecma_value_t value) /**< value to assign */ { JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (prop_p) == ECMA_PROPERTY_TYPE_NAMEDDATA); ecma_assert_object_contains_the_property (obj_p, prop_p); if (ecma_is_value_number (value) && ecma_is_value_number (ecma_get_named_data_property_value (prop_p))) { const ecma_number_t *num_src_p = ecma_get_number_from_value (value); ecma_number_t *num_dst_p = ecma_get_number_from_value (ecma_get_named_data_property_value (prop_p)); *num_dst_p = *num_src_p; } else { ecma_value_t v = ecma_get_named_data_property_value (prop_p); ecma_free_value_if_not_object (v); ecma_set_named_data_property_value (prop_p, ecma_copy_value_if_not_object (value)); } } /* ecma_named_data_property_assign_value */
/** * ArrayBuffer object creation operation. * * See also: ES2015 24.1.1.1 * * @return ecma value * Returned value must be freed with ecma_free_value */ ecma_value_t ecma_op_create_arraybuffer_object (const ecma_value_t *arguments_list_p, /**< list of arguments that * are passed to String constructor */ ecma_length_t arguments_list_len) /**< length of the arguments' list */ { JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); ecma_number_t length_num = 0; if (arguments_list_len > 0) { if (ecma_is_value_number (arguments_list_p[0])) { length_num = ecma_get_number_from_value (arguments_list_p[0]); } else { ecma_value_t to_number_value = ecma_op_to_number (arguments_list_p[0]); if (ECMA_IS_VALUE_ERROR (to_number_value)) { return to_number_value; } length_num = ecma_get_number_from_value (to_number_value); ecma_free_value (to_number_value); } if (ecma_number_is_nan (length_num)) { length_num = 0; } const uint32_t maximum_size_in_byte = UINT32_MAX - sizeof (ecma_extended_object_t) - JMEM_ALIGNMENT + 1; if (length_num <= -1.0 || length_num > (double) maximum_size_in_byte + 0.5) { return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid ArrayBuffer length.")); } } uint32_t length_uint32 = ecma_number_to_uint32 (length_num); return ecma_make_object_value (ecma_arraybuffer_new_object (length_uint32)); } /* ecma_op_create_arraybuffer_object */
/** * 'typeof' opcode handler. * * See also: ECMA-262 v5, 11.4.3 * * @return ecma value * Returned value must be freed with ecma_free_value */ ecma_value_t opfunc_typeof (ecma_value_t left_value) /**< left value */ { ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ecma_string_t *type_str_p = NULL; if (ecma_is_value_undefined (left_value)) { type_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_UNDEFINED); } else if (ecma_is_value_null (left_value)) { type_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_OBJECT); } else if (ecma_is_value_boolean (left_value)) { type_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_BOOLEAN); } else if (ecma_is_value_number (left_value)) { type_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_NUMBER); } else if (ecma_is_value_string (left_value)) { type_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_STRING); } else { JERRY_ASSERT (ecma_is_value_object (left_value)); if (ecma_op_is_callable (left_value)) { type_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_FUNCTION); } else { type_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_OBJECT); } } ret_value = ecma_make_string_value (type_str_p); return ret_value; } /* opfunc_typeof */
/** * 'Object' object creation operation with one argument. * * See also: ECMA-262 v5, 15.2.2.1 * * @return pointer to newly created 'Object' object */ ecma_completion_value_t ecma_op_create_object_object_arg (ecma_value_t value) /**< argument of constructor */ { ecma_check_value_type_is_spec_defined (value); if (ecma_is_value_object (value) || ecma_is_value_number (value) || ecma_is_value_string (value) || ecma_is_value_boolean (value)) { // 1.b, 1.c, 1.d return ecma_op_to_object (value); } else { // 2. JERRY_ASSERT (ecma_is_value_undefined (value) || ecma_is_value_null (value)); ecma_object_t *obj_p = ecma_op_create_object_object_noarg (); return ecma_make_normal_completion_value (ecma_make_object_value (obj_p)); } } /* ecma_op_create_object_object_arg */
/** * Array object creation operation. * * See also: ECMA-262 v5, 15.4.2.1 * ECMA-262 v5, 15.4.2.2 * * @return ecma value * Returned value must be freed with ecma_free_value */ ecma_value_t ecma_op_create_array_object (const ecma_value_t *arguments_list_p, /**< list of arguments that are passed to Array constructor */ ecma_length_t arguments_list_len, /**< length of the arguments' list */ bool is_treat_single_arg_as_length) /**< if the value is true, arguments_list_len is 1 and single argument is Number, then treat the single argument as new Array's length rather than as single item of the Array */ { JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); uint32_t length; const ecma_value_t *array_items_p; ecma_length_t array_items_count; if (is_treat_single_arg_as_length && arguments_list_len == 1 && ecma_is_value_number (arguments_list_p[0])) { ecma_number_t num = ecma_get_number_from_value (arguments_list_p[0]); uint32_t num_uint32 = ecma_number_to_uint32 (num); if (num != ((ecma_number_t) num_uint32)) { return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid array length.")); } else { length = num_uint32; array_items_p = NULL; array_items_count = 0; } } else { length = arguments_list_len; array_items_p = arguments_list_p; array_items_count = arguments_list_len; } #ifndef CONFIG_DISABLE_ARRAY_BUILTIN ecma_object_t *array_prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_ARRAY_PROTOTYPE); #else /* CONFIG_DISABLE_ARRAY_BUILTIN */ ecma_object_t *array_prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE); #endif /* !CONFIG_DISABLE_ARRAY_BUILTIN */ ecma_object_t *obj_p = ecma_create_object (array_prototype_obj_p, 0, ECMA_OBJECT_TYPE_ARRAY); ecma_deref_object (array_prototype_obj_p); /* * [[Class]] property is not stored explicitly for objects of ECMA_OBJECT_TYPE_ARRAY type. * * See also: ecma_object_get_class_name */ ecma_string_t *length_magic_string_p = ecma_new_ecma_length_string (); ecma_property_value_t *length_prop_value_p; length_prop_value_p = ecma_create_named_data_property (obj_p, length_magic_string_p, ECMA_PROPERTY_FLAG_WRITABLE, NULL); length_prop_value_p->value = ecma_make_number_value ((ecma_number_t) length); ecma_deref_ecma_string (length_magic_string_p); for (uint32_t index = 0; index < array_items_count; index++) { if (ecma_is_value_array_hole (array_items_p[index])) { continue; } ecma_string_t *item_name_string_p = ecma_new_ecma_string_from_uint32 (index); ecma_builtin_helper_def_prop (obj_p, item_name_string_p, array_items_p[index], true, /* Writable */ true, /* Enumerable */ true, /* Configurable */ false); /* Failure handling */ ecma_deref_ecma_string (item_name_string_p); } return ecma_make_object_value (obj_p); } /* ecma_op_create_array_object */
/** * ToNumber operation. * * See also: * ECMA-262 v5, 9.3 * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t ecma_op_to_number (ecma_value_t value) /**< ecma-value */ { ecma_check_value_type_is_spec_defined (value); if (ecma_is_value_number (value)) { return ecma_make_normal_completion_value (ecma_copy_value (value, true)); } else if (ecma_is_value_string (value)) { ecma_string_t *str_p = ecma_get_string_from_value (value); ecma_number_t *num_p = ecma_alloc_number (); *num_p = ecma_string_to_number (str_p); return ecma_make_normal_completion_value (ecma_make_number_value (num_p)); } else if (ecma_is_value_object (value)) { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); ECMA_TRY_CATCH (primitive_value, ecma_op_to_primitive (value, ECMA_PREFERRED_TYPE_NUMBER), ret_value); ret_value = ecma_op_to_number (primitive_value); ECMA_FINALIZE (primitive_value); return ret_value; } else { ecma_number_t *num_p = ecma_alloc_number (); if (ecma_is_value_undefined (value)) { *num_p = ecma_number_make_nan (); } else if (ecma_is_value_null (value)) { *num_p = ECMA_NUMBER_ZERO; } else { JERRY_ASSERT (ecma_is_value_boolean (value)); if (ecma_is_value_true (value)) { *num_p = ECMA_NUMBER_ONE; } else { *num_p = ECMA_NUMBER_ZERO; } } return ecma_make_normal_completion_value (ecma_make_number_value (num_p)); } } /* ecma_op_to_number */
/** * The Function.prototype object's 'bind' routine * * See also: * ECMA-262 v5, 15.3.4.5 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_function_prototype_object_bind (ecma_value_t this_arg, /**< this argument */ const ecma_value_t *arguments_list_p, /**< list of arguments */ ecma_length_t arguments_number) /**< number of arguments */ { ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); /* 2. */ if (!ecma_op_is_callable (this_arg)) { ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("")); } else { /* 4. 11. 18. */ ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE); ecma_object_t *function_p = ecma_create_object (prototype_obj_p, false, true, ECMA_OBJECT_TYPE_BOUND_FUNCTION); ecma_deref_object (prototype_obj_p); /* 7. */ ecma_value_t *target_function_prop_p; target_function_prop_p = ecma_create_internal_property (function_p, ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_TARGET_FUNCTION); ecma_object_t *this_arg_obj_p = ecma_get_object_from_value (this_arg); ECMA_SET_INTERNAL_VALUE_POINTER (*target_function_prop_p, this_arg_obj_p); /* 8. */ ecma_value_t *bound_this_prop_p; bound_this_prop_p = ecma_create_internal_property (function_p, ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_THIS); const ecma_length_t arg_count = arguments_number; if (arg_count > 0) { *bound_this_prop_p = ecma_copy_value_if_not_object (arguments_list_p[0]); } else { *bound_this_prop_p = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); } if (arg_count > 1) { ecma_collection_header_t *bound_args_collection_p; bound_args_collection_p = ecma_new_values_collection (&arguments_list_p[1], arg_count - 1, false); ecma_value_t *bound_args_prop_p; bound_args_prop_p = ecma_create_internal_property (function_p, ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_ARGS); ECMA_SET_INTERNAL_VALUE_POINTER (*bound_args_prop_p, bound_args_collection_p); } /* * [[Class]] property is not stored explicitly for objects of ECMA_OBJECT_TYPE_FUNCTION type. * * See also: ecma_object_get_class_name */ /* 16. */ ecma_number_t length = ECMA_NUMBER_ZERO; ecma_string_t *magic_string_length_p = ecma_new_ecma_length_string (); /* 15. */ if (ecma_object_get_class_name (this_arg_obj_p) == LIT_MAGIC_STRING_FUNCTION_UL) { ecma_value_t get_len_value = ecma_op_object_get (this_arg_obj_p, magic_string_length_p); JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (get_len_value)); JERRY_ASSERT (ecma_is_value_number (get_len_value)); const ecma_length_t bound_arg_count = arg_count > 1 ? arg_count - 1 : 0; /* 15.a */ length = ecma_get_number_from_value (get_len_value) - ((ecma_number_t) bound_arg_count); ecma_free_value (get_len_value); /* 15.b */ if (ecma_number_is_negative (length)) { length = ECMA_NUMBER_ZERO; } } /* 17. */ ecma_value_t completion = ecma_builtin_helper_def_prop (function_p, magic_string_length_p, ecma_make_number_value (length), false, /* Writable */ false, /* Enumerable */ false, /* Configurable */ false); /* Failure handling */ JERRY_ASSERT (ecma_is_value_boolean (completion)); ecma_deref_ecma_string (magic_string_length_p); /* 19-21. */ ecma_object_t *thrower_p = ecma_builtin_get (ECMA_BUILTIN_ID_TYPE_ERROR_THROWER); ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor (); { prop_desc.is_enumerable_defined = true; prop_desc.is_enumerable = false; prop_desc.is_configurable_defined = true; prop_desc.is_configurable = false; prop_desc.is_get_defined = true; prop_desc.get_p = thrower_p; prop_desc.is_set_defined = true; prop_desc.set_p = thrower_p; } ecma_string_t *magic_string_caller_p = ecma_get_magic_string (LIT_MAGIC_STRING_CALLER); completion = ecma_op_object_define_own_property (function_p, magic_string_caller_p, &prop_desc, false); JERRY_ASSERT (ecma_is_value_boolean (completion)); ecma_deref_ecma_string (magic_string_caller_p); ecma_string_t *magic_string_arguments_p = ecma_get_magic_string (LIT_MAGIC_STRING_ARGUMENTS); completion = ecma_op_object_define_own_property (function_p, magic_string_arguments_p, &prop_desc, false); JERRY_ASSERT (ecma_is_value_boolean (completion)); ecma_deref_ecma_string (magic_string_arguments_p); ecma_deref_object (thrower_p); /* 22. */ ret_value = ecma_make_object_value (function_p); } return ret_value; } /* ecma_builtin_function_prototype_object_bind */
/** * GetValue operation part (object base). * * See also: ECMA-262 v5, 8.7.1, section 4 * * @return ecma value * Returned value must be freed with ecma_free_value. */ ecma_value_t ecma_op_get_value_object_base (ecma_reference_t ref) /**< ECMA-reference */ { const ecma_value_t base = ref.base; const bool is_unresolvable_reference = ecma_is_value_undefined (base); const bool has_primitive_base = (ecma_is_value_boolean (base) || ecma_is_value_number (base) || ecma_is_value_string (base)); const bool has_object_base = (ecma_is_value_object (base) && !(ecma_is_lexical_environment (ecma_get_object_from_value (base)))); const bool is_property_reference = has_primitive_base || has_object_base; JERRY_ASSERT (!is_unresolvable_reference); JERRY_ASSERT (is_property_reference); ecma_string_t *referenced_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, ref.referenced_name_cp); // 4.a if (!has_primitive_base) { // 4.b case 1 ecma_object_t *obj_p = ecma_get_object_from_value (base); JERRY_ASSERT (obj_p != NULL && !ecma_is_lexical_environment (obj_p)); return ecma_op_object_get (obj_p, referenced_name_p); } else { // 4.b case 2 ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); // 1. ECMA_TRY_CATCH (obj_base, ecma_op_to_object (base), ret_value); ecma_object_t *obj_p = ecma_get_object_from_value (obj_base); JERRY_ASSERT (obj_p != NULL && !ecma_is_lexical_environment (obj_p)); // 2. ecma_property_t *prop_p = ecma_op_object_get_property (obj_p, referenced_name_p); if (prop_p == NULL) { // 3. ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); } else if (prop_p->flags & ECMA_PROPERTY_FLAG_NAMEDDATA) { // 4. ret_value = ecma_copy_value (ecma_get_named_data_property_value (prop_p), true); } else { // 5. JERRY_ASSERT (prop_p->flags & ECMA_PROPERTY_FLAG_NAMEDACCESSOR); ecma_object_t *obj_p = ecma_get_named_accessor_property_getter (prop_p); // 6. if (obj_p == NULL) { ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); } else { // 7. ret_value = ecma_op_function_call (obj_p, base, NULL, 0); } } ECMA_FINALIZE (obj_base); return ret_value; } } /* ecma_op_get_value_object_base */
/** * PutValue operation part (object base). * * See also: ECMA-262 v5, 8.7.2, section 4 * * @return ecma value * Returned value must be freed with ecma_free_value. */ ecma_value_t ecma_op_put_value_object_base (ecma_reference_t ref, /**< ECMA-reference */ ecma_value_t value) /**< ECMA-value */ { const ecma_value_t base = ref.base; const bool is_unresolvable_reference = ecma_is_value_undefined (base); const bool has_primitive_base = (ecma_is_value_boolean (base) || ecma_is_value_number (base) || ecma_is_value_string (base)); const bool has_object_base = (ecma_is_value_object (base) && !(ecma_is_lexical_environment (ecma_get_object_from_value (base)))); const bool is_property_reference = has_primitive_base || has_object_base; JERRY_ASSERT (!is_unresolvable_reference); JERRY_ASSERT (is_property_reference); // 4.a if (!has_primitive_base) { // 4.b case 1 ecma_object_t *obj_p = ecma_get_object_from_value (base); JERRY_ASSERT (obj_p != NULL && !ecma_is_lexical_environment (obj_p)); ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ECMA_TRY_CATCH (put_ret_value, ecma_op_object_put (obj_p, ECMA_GET_NON_NULL_POINTER (ecma_string_t, ref.referenced_name_cp), value, ref.is_strict), ret_value); ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ECMA_FINALIZE (put_ret_value); return ret_value; } else { // 4.b case 2 ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); // sub_1. ECMA_TRY_CATCH (obj_base, ecma_op_to_object (base), ret_value); ecma_object_t *obj_p = ecma_get_object_from_value (obj_base); JERRY_ASSERT (obj_p != NULL && !ecma_is_lexical_environment (obj_p)); ecma_string_t *referenced_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, ref.referenced_name_cp); // sub_2. if (!ecma_op_object_can_put (obj_p, referenced_name_p)) { ret_value = ecma_reject_put (ref.is_strict); } else { // sub_3. ecma_property_t *own_prop_p = ecma_op_object_get_own_property (obj_p, referenced_name_p); // sub_5. ecma_property_t *prop_p = ecma_op_object_get_property (obj_p, referenced_name_p); // sub_4., sub_7 if ((own_prop_p != NULL && (own_prop_p->flags & ECMA_PROPERTY_FLAG_NAMEDDATA)) || (prop_p == NULL) || !(prop_p->flags & ECMA_PROPERTY_FLAG_NAMEDACCESSOR)) { ret_value = ecma_reject_put (ref.is_strict); } else { // sub_6. JERRY_ASSERT (prop_p != NULL && (prop_p->flags & ECMA_PROPERTY_FLAG_NAMEDACCESSOR)); ecma_object_t *setter_p = ecma_get_named_accessor_property_setter (prop_p); JERRY_ASSERT (setter_p != NULL); ECMA_TRY_CATCH (call_ret, ecma_op_function_call (setter_p, base, &value, 1), ret_value); ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ECMA_FINALIZE (call_ret); } } ECMA_FINALIZE (obj_base); return ret_value; } } /* ecma_op_put_value_object_base */
/** * SameValue operation. * * See also: * ECMA-262 v5, 9.12 * * @return true - if the value are same according to ECMA-defined SameValue algorithm, * false - otherwise. */ bool ecma_op_same_value (ecma_value_t x, /**< ecma-value */ ecma_value_t y) /**< ecma-value */ { const bool is_x_undefined = ecma_is_value_undefined (x); const bool is_x_null = ecma_is_value_null (x); const bool is_x_boolean = ecma_is_value_boolean (x); const bool is_x_number = ecma_is_value_number (x); const bool is_x_string = ecma_is_value_string (x); const bool is_x_object = ecma_is_value_object (x); const bool is_y_undefined = ecma_is_value_undefined (y); const bool is_y_null = ecma_is_value_null (y); const bool is_y_boolean = ecma_is_value_boolean (y); const bool is_y_number = ecma_is_value_number (y); const bool is_y_string = ecma_is_value_string (y); const bool is_y_object = ecma_is_value_object (y); const bool is_types_equal = ((is_x_undefined && is_y_undefined) || (is_x_null && is_y_null) || (is_x_boolean && is_y_boolean) || (is_x_number && is_y_number) || (is_x_string && is_y_string) || (is_x_object && is_y_object)); if (!is_types_equal) { return false; } if (is_x_undefined || is_x_null) { return true; } if (is_x_number) { ecma_number_t *x_num_p = ecma_get_number_from_value (x); ecma_number_t *y_num_p = ecma_get_number_from_value (y); if (ecma_number_is_nan (*x_num_p) && ecma_number_is_nan (*y_num_p)) { return true; } else if (ecma_number_is_zero (*x_num_p) && ecma_number_is_zero (*y_num_p) && ecma_number_is_negative (*x_num_p) != ecma_number_is_negative (*y_num_p)) { return false; } return (*x_num_p == *y_num_p); } if (is_x_string) { ecma_string_t* x_str_p = ecma_get_string_from_value (x); ecma_string_t* y_str_p = ecma_get_string_from_value (y); return ecma_compare_ecma_strings (x_str_p, y_str_p); } if (is_x_boolean) { return (ecma_is_value_true (x) == ecma_is_value_true (y)); } JERRY_ASSERT (is_x_object); return (ecma_get_object_from_value (x) == ecma_get_object_from_value (y)); } /* ecma_op_same_value */
/** * Abstract operation 'Str' defined in 15.12.3 * * See also: * ECMA-262 v5, 15.12.3 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_json_str (ecma_string_t *key_p, /**< property key*/ ecma_object_t *holder_p, /**< the object*/ ecma_json_stringify_context_t *context_p) /**< context*/ { ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); /* 1. */ ECMA_TRY_CATCH (value, ecma_op_object_get (holder_p, key_p), ret_value); ecma_value_t my_val = ecma_copy_value (value, true); /* 2. */ if (ecma_is_value_object (my_val)) { ecma_object_t *value_obj_p = ecma_get_object_from_value (my_val); ecma_string_t *to_json_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_TO_JSON_UL); /* 2.a */ ECMA_TRY_CATCH (toJSON, ecma_op_object_get (value_obj_p, to_json_str_p), ret_value); /* 2.b */ if (ecma_op_is_callable (toJSON)) { ecma_value_t key_value = ecma_make_string_value (key_p); ecma_value_t call_args[] = { key_value }; ecma_object_t *toJSON_obj_p = ecma_get_object_from_value (toJSON); ECMA_TRY_CATCH (func_ret_val, ecma_op_function_call (toJSON_obj_p, my_val, call_args, 1), ret_value); ecma_free_value (my_val); my_val = ecma_copy_value (func_ret_val, true); ECMA_FINALIZE (func_ret_val); } ECMA_FINALIZE (toJSON); ecma_deref_ecma_string (to_json_str_p); } /* 3. */ if (context_p->replacer_function_p && ecma_is_value_empty (ret_value)) { ecma_value_t holder_value = ecma_make_object_value (holder_p); ecma_value_t key_value = ecma_make_string_value (key_p); ecma_value_t call_args[] = { key_value, my_val }; ECMA_TRY_CATCH (func_ret_val, ecma_op_function_call (context_p->replacer_function_p, holder_value, call_args, 2), ret_value); ecma_free_value (my_val); my_val = ecma_copy_value (func_ret_val, true); ECMA_FINALIZE (func_ret_val); } /* 4. */ if (ecma_is_value_object (my_val) && ecma_is_value_empty (ret_value)) { ecma_object_t *obj_p = ecma_get_object_from_value (my_val); lit_magic_string_id_t class_name = ecma_object_get_class_name (obj_p); /* 4.a */ if (class_name == LIT_MAGIC_STRING_NUMBER_UL) { ECMA_TRY_CATCH (val, ecma_op_to_number (my_val), ret_value); ecma_free_value (my_val); my_val = ecma_copy_value (val, true); ECMA_FINALIZE (val); } /* 4.b */ else if (class_name == LIT_MAGIC_STRING_STRING_UL) { ECMA_TRY_CATCH (val, ecma_op_to_string (my_val), ret_value); ecma_free_value (my_val); my_val = ecma_copy_value (val, true); ECMA_FINALIZE (val); } /* 4.c */ else if (class_name == LIT_MAGIC_STRING_BOOLEAN_UL) { ECMA_TRY_CATCH (val, ecma_op_to_primitive (my_val, ECMA_PREFERRED_TYPE_NO), ret_value); ecma_free_value (my_val); my_val = ecma_copy_value (val, true); ECMA_FINALIZE (val); } } if (ecma_is_value_empty (ret_value)) { /* 5. - 7. */ if (ecma_is_value_null (my_val) || ecma_is_value_boolean (my_val)) { ret_value = ecma_op_to_string (my_val); JERRY_ASSERT (!ecma_is_value_error (ret_value)); } /* 8. */ else if (ecma_is_value_string (my_val)) { ecma_string_t *value_str_p = ecma_get_string_from_value (my_val); ret_value = ecma_builtin_json_quote (value_str_p); } /* 9. */ else if (ecma_is_value_number (my_val)) { ecma_number_t num_value_p = *ecma_get_number_from_value (my_val); /* 9.a */ if (!ecma_number_is_nan (num_value_p) && !ecma_number_is_infinity (num_value_p)) { ret_value = ecma_op_to_string (my_val); JERRY_ASSERT (!ecma_is_value_error (ret_value)); } else { /* 9.b */ ecma_string_t *null_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_NULL); ret_value = ecma_make_string_value (null_str_p); } } /* 10. */ else if (ecma_is_value_object (my_val) && !ecma_op_is_callable (my_val)) { ecma_object_t *obj_p = ecma_get_object_from_value (my_val); lit_magic_string_id_t class_name = ecma_object_get_class_name (obj_p); /* 10.a */ if (class_name == LIT_MAGIC_STRING_ARRAY_UL) { ECMA_TRY_CATCH (val, ecma_builtin_json_array (obj_p, context_p), ret_value); ret_value = ecma_copy_value (val, true); ECMA_FINALIZE (val); } /* 10.b */ else { ECMA_TRY_CATCH (val, ecma_builtin_json_object (obj_p, context_p), ret_value); ret_value = ecma_copy_value (val, true); ECMA_FINALIZE (val); } } else { /* 11. */ ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); } } ecma_free_value (my_val); ECMA_FINALIZE (value); return ret_value; } /* ecma_builtin_json_str */
/** * ECMA abstract equality comparison routine. * * See also: ECMA-262 v5, 11.9.3 * * Note: * This function might raise an exception, so the * returned value must be freed with ecma_free_value. * * @return true - if values are equal, * false - otherwise * error - in case of any problems */ ecma_value_t ecma_op_abstract_equality_compare (ecma_value_t x, /**< first operand */ ecma_value_t y) /**< second operand */ { if (x == y) { return ECMA_VALUE_TRUE; } if (ecma_are_values_integer_numbers (x, y)) { /* Note: the (x == y) comparison captures the true case. */ return ECMA_VALUE_FALSE; } if (ecma_is_value_number (x)) { if (ecma_is_value_number (y)) { /* 1.c */ ecma_number_t x_num = ecma_get_number_from_value (x); ecma_number_t y_num = ecma_get_number_from_value (y); bool is_x_equal_to_y = (x_num == y_num); #ifndef JERRY_NDEBUG bool is_x_equal_to_y_check; if (ecma_number_is_nan (x_num) || ecma_number_is_nan (y_num)) { is_x_equal_to_y_check = false; } else if (x_num == y_num || (ecma_number_is_zero (x_num) && ecma_number_is_zero (y_num))) { is_x_equal_to_y_check = true; } else { is_x_equal_to_y_check = false; } JERRY_ASSERT (is_x_equal_to_y == is_x_equal_to_y_check); #endif /* !JERRY_NDEBUG */ return ecma_make_boolean_value (is_x_equal_to_y); } /* Swap values. */ ecma_value_t tmp = x; x = y; y = tmp; } if (ecma_is_value_string (x)) { if (ecma_is_value_string (y)) { /* 1., d. */ ecma_string_t *x_str_p = ecma_get_string_from_value (x); ecma_string_t *y_str_p = ecma_get_string_from_value (y); bool is_equal = ecma_compare_ecma_strings (x_str_p, y_str_p); return ecma_make_boolean_value (is_equal); } if (ecma_is_value_number (y)) { /* 4. */ ecma_value_t x_num_value = ecma_op_to_number (x); if (ECMA_IS_VALUE_ERROR (x_num_value)) { return x_num_value; } ecma_value_t compare_result = ecma_op_abstract_equality_compare (x_num_value, y); ecma_free_value (x_num_value); return compare_result; } /* Swap values. */ ecma_value_t tmp = x; x = y; y = tmp; } #if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) if (ecma_is_value_symbol (x)) { return ECMA_VALUE_FALSE; } #endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ if (ecma_is_value_boolean (y)) { if (ecma_is_value_boolean (x)) { /* 1., e. */ /* Note: the (x == y) comparison captures the true case. */ return ECMA_VALUE_FALSE; } /* 7. */ return ecma_op_abstract_equality_compare (x, ecma_make_integer_value (ecma_is_value_true (y) ? 1 : 0)); } if (ecma_is_value_object (x)) { if (ecma_is_value_string (y) #if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) || ecma_is_value_symbol (y) #endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ || ecma_is_value_number (y)) { /* 9. */ ecma_value_t x_prim_value = ecma_op_to_primitive (x, ECMA_PREFERRED_TYPE_NO); if (ECMA_IS_VALUE_ERROR (x_prim_value)) { return x_prim_value; } ecma_value_t compare_result = ecma_op_abstract_equality_compare (x_prim_value, y); ecma_free_value (x_prim_value); return compare_result; } /* 1., f. */ /* Note: the (x == y) comparison captures the true case. */ return ECMA_VALUE_FALSE; } if (ecma_is_value_boolean (x)) { /* 6. */ return ecma_op_abstract_equality_compare (ecma_make_integer_value (ecma_is_value_true (x) ? 1 : 0), y); } if (ecma_is_value_undefined (x) || ecma_is_value_null (x)) { /* 1. a., b. */ /* 2., 3. */ bool is_equal = ecma_is_value_undefined (y) || ecma_is_value_null (y); return ecma_make_boolean_value (is_equal); } return ECMA_VALUE_FALSE; } /* ecma_op_abstract_equality_compare */
/** * ECMA strict equality comparison routine. * * See also: ECMA-262 v5, 11.9.6 * * @return true - if values are strict equal, * false - otherwise */ bool ecma_op_strict_equality_compare (ecma_value_t x, /**< first operand */ ecma_value_t y) /**< second operand */ { if (ecma_is_value_direct (x) || ecma_is_value_direct (y) #if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) || ecma_is_value_symbol (x) || ecma_is_value_symbol (y) #endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ || ecma_is_value_object (x) || ecma_is_value_object (y)) { JERRY_ASSERT (!ecma_is_value_direct (x) || ecma_is_value_undefined (x) || ecma_is_value_null (x) || ecma_is_value_boolean (x) || ecma_is_value_integer_number (x)); JERRY_ASSERT (!ecma_is_value_direct (y) || ecma_is_value_undefined (y) || ecma_is_value_null (y) || ecma_is_value_boolean (y) || ecma_is_value_integer_number (y)); if ((x != ecma_make_integer_value (0) || !ecma_is_value_float_number (y)) && (y != ecma_make_integer_value (0) || !ecma_is_value_float_number (x))) { return (x == y); } /* The +0 === -0 case handled below. */ } JERRY_ASSERT (ecma_is_value_number (x) || ecma_is_value_string (x)); JERRY_ASSERT (ecma_is_value_number (y) || ecma_is_value_string (y)); if (ecma_is_value_string (x)) { if (!ecma_is_value_string (y)) { return false; } ecma_string_t *x_str_p = ecma_get_string_from_value (x); ecma_string_t *y_str_p = ecma_get_string_from_value (y); return ecma_compare_ecma_strings (x_str_p, y_str_p); } if (!ecma_is_value_number (y)) { return false; } ecma_number_t x_num = ecma_get_number_from_value (x); ecma_number_t y_num = ecma_get_number_from_value (y); bool is_x_equal_to_y = (x_num == y_num); #ifndef JERRY_NDEBUG bool is_x_equal_to_y_check; if (ecma_number_is_nan (x_num) || ecma_number_is_nan (y_num)) { is_x_equal_to_y_check = false; } else if (x_num == y_num || (ecma_number_is_zero (x_num) && ecma_number_is_zero (y_num))) { is_x_equal_to_y_check = true; } else { is_x_equal_to_y_check = false; } JERRY_ASSERT (is_x_equal_to_y == is_x_equal_to_y_check); #endif /* !JERRY_NDEBUG */ return is_x_equal_to_y; } /* ecma_op_strict_equality_compare */
/** * The JSON object's 'stringify' routine * * See also: * ECMA-262 v5, 15.12.3 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_json_stringify (ecma_value_t this_arg __attr_unused___, /**< 'this' argument */ ecma_value_t arg1, /**< value */ ecma_value_t arg2, /**< replacer */ ecma_value_t arg3) /**< space */ { ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ecma_json_stringify_context_t context; /* 1. */ context.occurence_stack_p = ecma_new_values_collection (NULL, 0, false); /* 2. */ context.indent_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); /* 3. */ context.property_list_p = ecma_new_values_collection (NULL, 0, false); context.replacer_function_p = NULL; /* 4. */ if (ecma_is_value_object (arg2)) { ecma_object_t *obj_p = ecma_get_object_from_value (arg2); /* 4.a */ if (ecma_op_is_callable (arg2)) { context.replacer_function_p = obj_p; } /* 4.b */ else if (ecma_object_get_class_name (obj_p) == LIT_MAGIC_STRING_ARRAY_UL) { ecma_string_t *length_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); ECMA_TRY_CATCH (array_length, ecma_op_object_get (obj_p, length_str_p), ret_value); ECMA_OP_TO_NUMBER_TRY_CATCH (array_length_num, array_length, ret_value); uint32_t array_length = ecma_number_to_uint32 (array_length_num); uint32_t index = 0; /* 4.b.ii */ while ((index < array_length) && ecma_is_value_empty (ret_value)) { ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (index); ECMA_TRY_CATCH (value, ecma_op_object_get (obj_p, index_str_p), ret_value); /* 4.b.ii.1 */ ecma_value_t item = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); /* 4.b.ii.2 */ if (ecma_is_value_string (value)) { item = ecma_copy_value (value, true); } /* 4.b.ii.3 */ else if (ecma_is_value_number (value)) { ECMA_TRY_CATCH (str_val, ecma_op_to_string (value), ret_value); item = ecma_copy_value (str_val, true); ECMA_FINALIZE (str_val); } /* 4.b.ii.4 */ else if (ecma_is_value_object (value)) { ecma_object_t *obj_val_p = ecma_get_object_from_value (value); lit_magic_string_id_t class_name = ecma_object_get_class_name (obj_val_p); /* 4.b.ii.4.a */ if (class_name == LIT_MAGIC_STRING_NUMBER_UL || class_name == LIT_MAGIC_STRING_STRING_UL) { ECMA_TRY_CATCH (val, ecma_op_to_string (value), ret_value); item = ecma_copy_value (val, true); ECMA_FINALIZE (val); } } /* 4.b.ii.5 */ if (!ecma_is_value_undefined (item)) { if (!ecma_has_string_value_in_collection (context.property_list_p, item)) { ecma_append_to_values_collection (context.property_list_p, item, true); ecma_deref_ecma_string (ecma_get_string_from_value (item)); } else { ecma_free_value (item); } } ECMA_FINALIZE (value); ecma_deref_ecma_string (index_str_p); index++; } ECMA_OP_TO_NUMBER_FINALIZE (array_length_num); ECMA_FINALIZE (array_length); ecma_deref_ecma_string (length_str_p); } } if (ecma_is_value_empty (ret_value)) { ecma_value_t space = ecma_copy_value (arg3, true); /* 5. */ if (ecma_is_value_object (arg3)) { ecma_object_t *obj_p = ecma_get_object_from_value (arg3); lit_magic_string_id_t class_name = ecma_object_get_class_name (obj_p); /* 5.a */ if (class_name == LIT_MAGIC_STRING_NUMBER_UL) { ECMA_TRY_CATCH (val, ecma_op_to_number (arg3), ret_value); ecma_free_value (space); space = ecma_copy_value (val, true); ECMA_FINALIZE (val); } /* 5.b */ else if (class_name == LIT_MAGIC_STRING_STRING_UL) { ECMA_TRY_CATCH (val, ecma_op_to_string (arg3), ret_value); ecma_free_value (space); space = ecma_copy_value (val, true); ECMA_FINALIZE (val); } } if (ecma_is_value_empty (ret_value)) { /* 6. */ if (ecma_is_value_number (space)) { ECMA_OP_TO_NUMBER_TRY_CATCH (array_length_num, arg3, ret_value); /* 6.a */ int32_t num_of_spaces = ecma_number_to_int32 (array_length_num); int32_t space = (num_of_spaces > 10) ? 10 : num_of_spaces; /* 6.b */ if (space < 1) { context.gap_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); } else { MEM_DEFINE_LOCAL_ARRAY (space_buff, space, char); for (int32_t i = 0; i < space; i++) { space_buff[i] = LIT_CHAR_SP; } context.gap_str_p = ecma_new_ecma_string_from_utf8 ((lit_utf8_byte_t *) space_buff, (lit_utf8_size_t) space); MEM_FINALIZE_LOCAL_ARRAY (space_buff); } ECMA_OP_TO_NUMBER_FINALIZE (array_length_num); } /* 7. */ else if (ecma_is_value_string (space)) { ecma_string_t *space_str_p = ecma_get_string_from_value (space); ecma_length_t num_of_chars = ecma_string_get_length (space_str_p); if (num_of_chars < 10) { context.gap_str_p = ecma_copy_or_ref_ecma_string (space_str_p); } else { context.gap_str_p = ecma_string_substr (space_str_p, 0, 10); } } /* 8. */ else { context.gap_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); } } ecma_free_value (space); if (ecma_is_value_empty (ret_value)) { /* 9. */ ecma_object_t *obj_wrapper_p = ecma_op_create_object_object_noarg (); ecma_string_t *empty_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); /* 10. */ ecma_value_t put_comp_val = ecma_op_object_put (obj_wrapper_p, empty_str_p, arg1, false); JERRY_ASSERT (ecma_is_value_true (put_comp_val)); ecma_free_value (put_comp_val); /* 11. */ ECMA_TRY_CATCH (str_val, ecma_builtin_json_str (empty_str_p, obj_wrapper_p, &context), ret_value); ret_value = ecma_copy_value (str_val, true); ECMA_FINALIZE (str_val); ecma_deref_object (obj_wrapper_p); ecma_deref_ecma_string (empty_str_p); } ecma_deref_ecma_string (context.gap_str_p); } ecma_deref_ecma_string (context.indent_str_p); ecma_free_values_collection (context.property_list_p, true); ecma_free_values_collection (context.occurence_stack_p, true); return ret_value; } /* ecma_builtin_json_stringify */
/** * SameValue operation. * * See also: * ECMA-262 v5, 9.12 * * @return true - if the value are same according to ECMA-defined SameValue algorithm, * false - otherwise. */ bool ecma_op_same_value (ecma_value_t x, /**< ecma value */ ecma_value_t y) /**< ecma value */ { const bool is_x_undefined = ecma_is_value_undefined (x); const bool is_x_null = ecma_is_value_null (x); const bool is_x_boolean = ecma_is_value_boolean (x); const bool is_x_number = ecma_is_value_number (x); const bool is_x_string = ecma_is_value_string (x); const bool is_x_object = ecma_is_value_object (x); const bool is_y_undefined = ecma_is_value_undefined (y); const bool is_y_null = ecma_is_value_null (y); const bool is_y_boolean = ecma_is_value_boolean (y); const bool is_y_number = ecma_is_value_number (y); const bool is_y_string = ecma_is_value_string (y); const bool is_y_object = ecma_is_value_object (y); const bool is_types_equal = ((is_x_undefined && is_y_undefined) || (is_x_null && is_y_null) || (is_x_boolean && is_y_boolean) || (is_x_number && is_y_number) || (is_x_string && is_y_string) || (is_x_object && is_y_object)); if (!is_types_equal) { return false; } else if (is_x_undefined || is_x_null) { return true; } else if (is_x_number) { ecma_number_t x_num = ecma_get_number_from_value (x); ecma_number_t y_num = ecma_get_number_from_value (y); bool is_x_nan = ecma_number_is_nan (x_num); bool is_y_nan = ecma_number_is_nan (y_num); if (is_x_nan || is_y_nan) { /* * If both are NaN * return true; * else * // one of the numbers is NaN, and another - is not * return false; */ return (is_x_nan && is_y_nan); } else if (ecma_number_is_zero (x_num) && ecma_number_is_zero (y_num) && ecma_number_is_negative (x_num) != ecma_number_is_negative (y_num)) { return false; } else { return (x_num == y_num); } } else if (is_x_string) { ecma_string_t *x_str_p = ecma_get_string_from_value (x); ecma_string_t *y_str_p = ecma_get_string_from_value (y); return ecma_compare_ecma_strings (x_str_p, y_str_p); } else if (is_x_boolean) { return (ecma_is_value_true (x) == ecma_is_value_true (y)); } else { JERRY_ASSERT (is_x_object); return (ecma_get_object_from_value (x) == ecma_get_object_from_value (y)); } } /* ecma_op_same_value */
/** * Update the length of an array to a new length * * @return ecma value * Returned value must be freed with ecma_free_value */ extern ecma_value_t ecma_op_array_object_set_length (ecma_object_t *object_p, /**< the array object */ ecma_value_t new_value, /**< new length value */ uint32_t flags) /**< configuration options */ { bool is_throw = (flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_IS_THROW); ecma_value_t completion = ecma_op_to_number (new_value); if (ECMA_IS_VALUE_ERROR (completion)) { return completion; } JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (completion) && ecma_is_value_number (completion)); ecma_number_t new_len_num = ecma_get_number_from_value (completion); ecma_free_value (completion); if (ecma_is_value_object (new_value)) { ecma_value_t compared_num_val = ecma_op_to_number (new_value); if (ECMA_IS_VALUE_ERROR (completion)) { return compared_num_val; } new_len_num = ecma_get_number_from_value (compared_num_val); ecma_free_value (compared_num_val); } uint32_t new_len_uint32 = ecma_number_to_uint32 (new_len_num); if (((ecma_number_t) new_len_uint32) != new_len_num) { return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid array length.")); } if (flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_REJECT) { return ecma_reject (is_throw); } ecma_string_t magic_string_length; ecma_init_ecma_length_string (&magic_string_length); ecma_property_t *len_prop_p = ecma_find_named_property (object_p, &magic_string_length); JERRY_ASSERT (len_prop_p != NULL && ECMA_PROPERTY_GET_TYPE (*len_prop_p) == ECMA_PROPERTY_TYPE_NAMEDDATA); ecma_property_value_t *len_prop_value_p = ECMA_PROPERTY_VALUE_PTR (len_prop_p); uint32_t old_len_uint32 = ecma_get_uint32_from_value (len_prop_value_p->value); if (new_len_num == old_len_uint32) { /* Only the writable flag must be updated. */ if (flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE_DEFINED) { if (!(flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE)) { ecma_set_property_writable_attr (len_prop_p, false); } else if (!ecma_is_property_writable (*len_prop_p)) { return ecma_reject (is_throw); } } return ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE); } else if (!ecma_is_property_writable (*len_prop_p)) { return ecma_reject (is_throw); } uint32_t current_len_uint32 = new_len_uint32; if (new_len_uint32 < old_len_uint32) { current_len_uint32 = ecma_delete_array_properties (object_p, new_len_uint32, old_len_uint32); } ecma_value_assign_uint32 (&len_prop_value_p->value, current_len_uint32); if ((flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE_DEFINED) && !(flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE)) { ecma_set_property_writable_attr (len_prop_p, false); } if (current_len_uint32 == new_len_uint32) { return ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE); } return ecma_reject (is_throw); } /* ecma_op_array_object_set_length */
/** * [[DefineOwnProperty]] ecma array object's operation * * See also: * ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8 * ECMA-262 v5, 15.4.5.1 * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t ecma_op_array_object_define_own_property (ecma_object_t *obj_p, /**< the array object */ ecma_string_t *property_name_p, /**< property name */ const ecma_property_descriptor_t *property_desc_p, /**< property descriptor */ bool is_throw) /**< flag that controls failure handling */ { JERRY_ASSERT (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY); // 1. ecma_string_t *magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); ecma_property_t *len_prop_p = ecma_op_object_get_own_property (obj_p, magic_string_length_p); JERRY_ASSERT (len_prop_p != NULL && len_prop_p->type == ECMA_PROPERTY_NAMEDDATA); // 2. ecma_value_t old_len_value = ecma_get_named_data_property_value (len_prop_p); ecma_number_t *num_p = ecma_get_number_from_value (old_len_value); uint32_t old_len_uint32 = ecma_number_to_uint32 (*num_p); // 3. bool is_property_name_equal_length = ecma_compare_ecma_strings (property_name_p, magic_string_length_p); ecma_deref_ecma_string (magic_string_length_p); if (is_property_name_equal_length) { // a. if (!property_desc_p->is_value_defined) { // i. return ecma_op_general_object_define_own_property (obj_p, property_name_p, property_desc_p, is_throw); } ecma_number_t new_len_num; // c. ecma_completion_value_t completion = ecma_op_to_number (property_desc_p->value); if (ecma_is_completion_value_throw (completion)) { return completion; } JERRY_ASSERT (ecma_is_completion_value_normal (completion) && ecma_is_value_number (ecma_get_completion_value_value (completion))); new_len_num = *ecma_get_number_from_completion_value (completion); ecma_free_completion_value (completion); uint32_t new_len_uint32 = ecma_number_to_uint32 (new_len_num); // d. if (ecma_uint32_to_number (new_len_uint32) != new_len_num) { return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_RANGE)); } else { // b., e. ecma_number_t *new_len_num_p = ecma_alloc_number (); *new_len_num_p = new_len_num; ecma_property_descriptor_t new_len_property_desc = *property_desc_p; new_len_property_desc.value = ecma_make_number_value (new_len_num_p); ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); // f. if (new_len_uint32 >= old_len_uint32) { // i. magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); ret_value = ecma_op_general_object_define_own_property (obj_p, magic_string_length_p, &new_len_property_desc, is_throw); ecma_deref_ecma_string (magic_string_length_p); } else { // g. if (!ecma_is_property_writable (len_prop_p)) { ret_value = ecma_reject (is_throw); } else { // h. bool new_writable; if (!new_len_property_desc.is_writable_defined || new_len_property_desc.is_writable) { new_writable = true; } else { // ii. new_writable = false; // iii. new_len_property_desc.is_writable_defined = true; new_len_property_desc.is_writable = true; } // j. magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); ecma_completion_value_t succeeded = ecma_op_general_object_define_own_property (obj_p, magic_string_length_p, &new_len_property_desc, is_throw); ecma_deref_ecma_string (magic_string_length_p); /* Handling normal false and throw values */ if (!ecma_is_completion_value_normal_true (succeeded)) { JERRY_ASSERT (ecma_is_completion_value_normal_false (succeeded) || ecma_is_completion_value_throw (succeeded)); // k. ret_value = succeeded; } else { // l JERRY_ASSERT (new_len_uint32 < old_len_uint32); /* * Item i. is replaced with faster iteration: only indices that actually exist in the array, are iterated */ bool is_reduce_succeeded = true; ecma_collection_header_t *array_index_props_p = ecma_op_object_get_property_names (obj_p, true, false, false); ecma_length_t array_index_props_num = array_index_props_p->unit_number; MEM_DEFINE_LOCAL_ARRAY (array_index_values_p, array_index_props_num, uint32_t); ecma_collection_iterator_t iter; ecma_collection_iterator_init (&iter, array_index_props_p); uint32_t array_index_values_pos = 0; while (ecma_collection_iterator_next (&iter)) { ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); uint32_t index; bool is_index = ecma_string_get_array_index (property_name_p, &index); JERRY_ASSERT (is_index); JERRY_ASSERT (index < old_len_uint32); array_index_values_p[array_index_values_pos++] = index; } JERRY_ASSERT (array_index_values_pos == array_index_props_num); while (array_index_values_pos != 0 && array_index_values_p[--array_index_values_pos] >= new_len_uint32) { uint32_t index = array_index_values_p[array_index_values_pos]; // ii. ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index); ecma_completion_value_t delete_succeeded = ecma_op_object_delete (obj_p, index_string_p, false); ecma_deref_ecma_string (index_string_p); if (ecma_is_completion_value_normal_false (delete_succeeded)) { // iii. new_len_uint32 = (index + 1u); ecma_number_t *new_len_num_p = ecma_get_number_from_value (new_len_property_desc.value); // 1. *new_len_num_p = ecma_uint32_to_number (index + 1u); // 2. if (!new_writable) { new_len_property_desc.is_writable_defined = true; new_len_property_desc.is_writable = false; } // 3. ecma_string_t *magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); ecma_completion_value_t completion = ecma_op_general_object_define_own_property (obj_p, magic_string_length_p, &new_len_property_desc, false); ecma_deref_ecma_string (magic_string_length_p); JERRY_ASSERT (ecma_is_completion_value_normal_true (completion) || ecma_is_completion_value_normal_false (completion)); is_reduce_succeeded = false; break; } } MEM_FINALIZE_LOCAL_ARRAY (array_index_values_p); ecma_free_values_collection (array_index_props_p, true); if (!is_reduce_succeeded) { ret_value = ecma_reject (is_throw); } else { // m. if (!new_writable) { ecma_property_descriptor_t prop_desc_not_writable = ecma_make_empty_property_descriptor (); prop_desc_not_writable.is_writable_defined = true; prop_desc_not_writable.is_writable = false; ecma_completion_value_t completion_set_not_writable; magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); completion_set_not_writable = ecma_op_general_object_define_own_property (obj_p, magic_string_length_p, &prop_desc_not_writable, false); ecma_deref_ecma_string (magic_string_length_p); JERRY_ASSERT (ecma_is_completion_value_normal_true (completion_set_not_writable)); } ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE); } } } } ecma_dealloc_number (new_len_num_p); return ret_value; } JERRY_UNREACHABLE (); } else { // 4.a. uint32_t index; if (!ecma_string_get_array_index (property_name_p, &index)) { // 5. return ecma_op_general_object_define_own_property (obj_p, property_name_p, property_desc_p, is_throw); } // 4. // b. if (index >= old_len_uint32 && !ecma_is_property_writable (len_prop_p)) { return ecma_reject (is_throw); } // c. ecma_completion_value_t succeeded = ecma_op_general_object_define_own_property (obj_p, property_name_p, property_desc_p, false); // d. JERRY_ASSERT (ecma_is_completion_value_normal_true (succeeded) || ecma_is_completion_value_normal_false (succeeded)); if (ecma_is_completion_value_normal_false (succeeded)) { return ecma_reject (is_throw); } // e. if (index >= old_len_uint32) { // i., ii. ecma_number_t *num_p = ecma_alloc_number (); *num_p = ecma_number_add (ecma_uint32_to_number (index), ECMA_NUMBER_ONE); ecma_named_data_property_assign_value (obj_p, len_prop_p, ecma_make_number_value (num_p)); ecma_dealloc_number (num_p); } // f. return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE); } JERRY_UNREACHABLE (); } /* ecma_op_array_object_define_own_property */
/** * Array object creation operation. * * See also: ECMA-262 v5, 15.4.2.1 * ECMA-262 v5, 15.4.2.2 * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t ecma_op_create_array_object (const ecma_value_t *arguments_list_p, /**< list of arguments that are passed to Array constructor */ ecma_length_t arguments_list_len, /**< length of the arguments' list */ bool is_treat_single_arg_as_length) /**< if the value is true, arguments_list_len is 1 and single argument is Number, then treat the single argument as new Array's length rather than as single item of the Array */ { JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); uint32_t length; const ecma_value_t *array_items_p; ecma_length_t array_items_count; if (is_treat_single_arg_as_length && arguments_list_len == 1 && ecma_is_value_number (arguments_list_p[0])) { ecma_number_t *num_p = ecma_get_number_from_value (arguments_list_p[0]); uint32_t num_uint32 = ecma_number_to_uint32 (*num_p); if (*num_p != ecma_uint32_to_number (num_uint32)) { return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_RANGE)); } else { length = num_uint32; array_items_p = NULL; array_items_count = 0; } } else { length = arguments_list_len; array_items_p = arguments_list_p; array_items_count = arguments_list_len; } #ifndef CONFIG_ECMA_COMPACT_PROFILE_DISABLE_ARRAY_BUILTIN ecma_object_t *array_prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_ARRAY_PROTOTYPE); #else /* !CONFIG_ECMA_COMPACT_PROFILE_DISABLE_ARRAY_BUILTIN */ ecma_object_t *array_prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE); #endif /* CONFIG_ECMA_COMPACT_PROFILE_DISABLE_ARRAY_BUILTIN */ ecma_object_t *obj_p = ecma_create_object (array_prototype_obj_p, true, ECMA_OBJECT_TYPE_ARRAY); ecma_deref_object (array_prototype_obj_p); /* * [[Class]] property is not stored explicitly for objects of ECMA_OBJECT_TYPE_ARRAY type. * * See also: ecma_object_get_class_name */ ecma_string_t *length_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); ecma_number_t *length_num_p = ecma_alloc_number (); *length_num_p = ecma_uint32_to_number (length); ecma_property_t *length_prop_p = ecma_create_named_data_property (obj_p, length_magic_string_p, true, false, false); ecma_set_named_data_property_value (length_prop_p, ecma_make_number_value (length_num_p)); ecma_deref_ecma_string (length_magic_string_p); for (uint32_t index = 0; index < array_items_count; index++) { if (ecma_is_value_array_hole (array_items_p[index])) { continue; } ecma_string_t *item_name_string_p = ecma_new_ecma_string_from_uint32 (index); ecma_builtin_helper_def_prop (obj_p, item_name_string_p, array_items_p[index], true, /* Writable */ true, /* Enumerable */ true, /* Configurable */ false); /* Failure handling */ ecma_deref_ecma_string (item_name_string_p); } return ecma_make_normal_completion_value (ecma_make_object_value (obj_p)); } /* ecma_op_create_array_object */
/** * [[DefineOwnProperty]] ecma array object's operation * * See also: * ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8 * ECMA-262 v5, 15.4.5.1 * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t ecma_op_array_object_define_own_property (ecma_object_t *obj_p, /**< the array object */ ecma_string_t *property_name_p, /**< property name */ const ecma_property_descriptor_t* property_desc_p, /**< property descriptor */ bool is_throw) /**< flag that controls failure handling */ { JERRY_ASSERT (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY); // 1. ecma_string_t* magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); ecma_property_t *len_prop_p = ecma_op_object_get_own_property (obj_p, magic_string_length_p); JERRY_ASSERT (len_prop_p != NULL && len_prop_p->type == ECMA_PROPERTY_NAMEDDATA); // 2. ecma_value_t old_len_value = ecma_get_named_data_property_value (len_prop_p); ecma_number_t *num_p = ecma_get_number_from_value (old_len_value); uint32_t old_len_uint32 = ecma_number_to_uint32 (*num_p); // 3. bool is_property_name_equal_length = ecma_compare_ecma_strings (property_name_p, magic_string_length_p); ecma_deref_ecma_string (magic_string_length_p); if (is_property_name_equal_length) { // a. if (!property_desc_p->is_value_defined) { // i. return ecma_op_general_object_define_own_property (obj_p, property_name_p, property_desc_p, is_throw); } ecma_number_t new_len_num; // c. ecma_completion_value_t completion = ecma_op_to_number (property_desc_p->value); if (ecma_is_completion_value_throw (completion)) { return completion; } JERRY_ASSERT (ecma_is_completion_value_normal (completion) && ecma_is_value_number (ecma_get_completion_value_value (completion))); new_len_num = *ecma_get_number_from_completion_value (completion); ecma_free_completion_value (completion); uint32_t new_len_uint32 = ecma_number_to_uint32 (new_len_num); // d. if (ecma_uint32_to_number (new_len_uint32) != new_len_num) { return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_RANGE)); } else { // b., e. ecma_number_t *new_len_num_p = ecma_alloc_number (); *new_len_num_p = new_len_num; ecma_property_descriptor_t new_len_property_desc = *property_desc_p; new_len_property_desc.value = ecma_make_number_value (new_len_num_p); ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); // f. if (new_len_uint32 >= old_len_uint32) { // i. magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); ret_value = ecma_op_general_object_define_own_property (obj_p, magic_string_length_p, &new_len_property_desc, is_throw); ecma_deref_ecma_string (magic_string_length_p); } else { // g. if (!ecma_is_property_writable (len_prop_p)) { ret_value = ecma_reject (is_throw); } else { // h. bool new_writable; if (!new_len_property_desc.is_writable_defined || new_len_property_desc.is_writable) { new_writable = true; } else { // ii. new_writable = false; // iii. new_len_property_desc.is_writable_defined = true; new_len_property_desc.is_writable = true; } // j. magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); ecma_completion_value_t succeeded = ecma_op_general_object_define_own_property (obj_p, magic_string_length_p, &new_len_property_desc, is_throw); ecma_deref_ecma_string (magic_string_length_p); /* Handling normal false and throw values */ if (!ecma_is_completion_value_normal_true (succeeded)) { JERRY_ASSERT (ecma_is_completion_value_normal_false (succeeded) || ecma_is_completion_value_throw (succeeded)); // k. ret_value = succeeded; } else { // l JERRY_ASSERT (new_len_uint32 < old_len_uint32); bool reduce_succeeded = true; while (new_len_uint32 < old_len_uint32) { // i old_len_uint32--; // ii ecma_string_t *old_length_string_p = ecma_new_ecma_string_from_uint32 (old_len_uint32); ecma_completion_value_t delete_succeeded = ecma_op_object_delete (obj_p, old_length_string_p, false); ecma_deref_ecma_string (old_length_string_p); // iii if (ecma_is_completion_value_normal_false (delete_succeeded)) { JERRY_ASSERT (ecma_is_value_number (new_len_property_desc.value)); ecma_number_t *new_len_num_p = ecma_get_number_from_value (new_len_property_desc.value); // 1. *new_len_num_p = ecma_uint32_to_number (old_len_uint32 + 1); // 2. if (!new_writable) { new_len_property_desc.is_writable_defined = true; new_len_property_desc.is_writable = false; } // 3. ecma_string_t *magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); ecma_completion_value_t completion = ecma_op_general_object_define_own_property (obj_p, magic_string_length_p, &new_len_property_desc, false); ecma_deref_ecma_string (magic_string_length_p); JERRY_ASSERT (ecma_is_completion_value_normal_true (completion) || ecma_is_completion_value_normal_false (completion)); reduce_succeeded = false; break; } } if (!reduce_succeeded) { ret_value = ecma_reject (is_throw); } else { // m. if (!new_writable) { ecma_property_descriptor_t prop_desc_not_writable = ecma_make_empty_property_descriptor (); prop_desc_not_writable.is_writable_defined = true; prop_desc_not_writable.is_writable = false; ecma_completion_value_t completion_set_not_writable; magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); completion_set_not_writable = ecma_op_general_object_define_own_property (obj_p, magic_string_length_p, &prop_desc_not_writable, false); ecma_deref_ecma_string (magic_string_length_p); JERRY_ASSERT (ecma_is_completion_value_normal_true (completion_set_not_writable)); } ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE); } } } } ecma_dealloc_number (new_len_num_p); return ret_value; } JERRY_UNREACHABLE (); } else { // 4.a. uint32_t index; if (!ecma_string_get_array_index (property_name_p, &index)) { // 5. return ecma_op_general_object_define_own_property (obj_p, property_name_p, property_desc_p, is_throw); } // 4. // b. if (index >= old_len_uint32 && !ecma_is_property_writable (len_prop_p)) { return ecma_reject (is_throw); } // c. ecma_completion_value_t succeeded = ecma_op_general_object_define_own_property (obj_p, property_name_p, property_desc_p, false); // d. JERRY_ASSERT (ecma_is_completion_value_normal_true (succeeded) || ecma_is_completion_value_normal_false (succeeded)); if (ecma_is_completion_value_normal_false (succeeded)) { return ecma_reject (is_throw); } // e. if (index >= old_len_uint32) { // i., ii. ecma_number_t *num_p = ecma_alloc_number (); *num_p = ecma_number_add (ecma_uint32_to_number (index), ECMA_NUMBER_ONE); ecma_named_data_property_assign_value (obj_p, len_prop_p, ecma_make_number_value (num_p)); ecma_dealloc_number (num_p); } // f. return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE); } JERRY_UNREACHABLE (); } /* ecma_op_array_object_define_own_property */