Array.prototype.sort() now handles defined properties only.

JerryScript-DCO-1.0-Signed-off-by: Dániel Bátyai dbatyai.u-szeged@partner.samsung.com
This commit is contained in:
Dániel Bátyai 2015-07-14 13:25:11 +02:00 committed by Evgeny Gavrin
parent 9d6e7bf336
commit a2c6663d43
4 changed files with 112 additions and 38 deletions

View File

@ -992,6 +992,39 @@ ecma_string_to_number (const ecma_string_t *str_p) /**< ecma-string */
JERRY_UNREACHABLE ();
} /* ecma_string_to_number */
/**
* Check if string is array index.
*
* @return true - if string is valid array index
* false - otherwise
*/
bool
ecma_string_get_array_index (const ecma_string_t *str_p, /**< ecma-string */
uint32_t *out_index_p) /**< out: index */
{
bool is_array_index = true;
if (str_p->container == ECMA_STRING_CONTAINER_UINT32_IN_DESC)
{
*out_index_p = str_p->u.uint32_number;
}
else
{
ecma_number_t num = ecma_string_to_number (str_p);
*out_index_p = ecma_number_to_uint32 (num);
ecma_string_t *to_uint32_to_string_p = ecma_new_ecma_string_from_uint32 (*out_index_p);
is_array_index = ecma_compare_ecma_strings (str_p,
to_uint32_to_string_p);
ecma_deref_ecma_string (to_uint32_to_string_p);
}
is_array_index = is_array_index && (*out_index_p != ECMA_MAX_VALUE_OF_VALID_ARRAY_INDEX);
return is_array_index;
} /* ecma_string_is_array_index */
/**
* Convert ecma-string's contents to a utf-8 string and put it to the buffer.
*

View File

@ -125,6 +125,7 @@ extern ecma_string_t* ecma_copy_or_ref_ecma_string (ecma_string_t *string_desc_p
extern void ecma_deref_ecma_string (ecma_string_t *string_p);
extern void ecma_check_that_ecma_string_need_not_be_freed (const ecma_string_t *string_p);
extern ecma_number_t ecma_string_to_number (const ecma_string_t *str_p);
extern bool ecma_string_get_array_index (const ecma_string_t *str_p, uint32_t *index);
extern ssize_t ecma_string_to_utf8_string (const ecma_string_t *string_desc_p,
lit_utf8_byte_t *buffer_p,
ssize_t buffer_size);

View File

@ -1449,36 +1449,75 @@ ecma_builtin_array_prototype_object_sort (ecma_value_t this_arg, /**< this argum
uint32_t len = ecma_number_to_uint32 (len_number);
uint32_t defined_prop_count = 0;
/* Count number of defined properties. */
/* Count number of array index properties. */
for (ecma_property_t *property_p = ecma_get_property_list (obj_p);
property_p != NULL;
property_p = ECMA_GET_POINTER (ecma_property_t, property_p->next_property_p))
{
defined_prop_count++;
ecma_string_t *property_name_p;
if (property_p->type == ECMA_PROPERTY_NAMEDDATA)
{
property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t,
property_p->u.named_data_property.name_p);
}
else if (property_p->type == ECMA_PROPERTY_NAMEDACCESSOR)
{
property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t,
property_p->u.named_accessor_property.name_p);
}
else
{
continue;
}
uint32_t index;
if (ecma_string_get_array_index (property_name_p, &index) && index < len)
{
defined_prop_count++;
}
}
MEM_DEFINE_LOCAL_ARRAY (values_buffer, defined_prop_count, ecma_value_t);
uint32_t copied_num = 0;
/* Copy unsorted array into a native c array. */
for (uint32_t index = 0; index < len && ecma_is_completion_value_empty (ret_value); index++)
for (ecma_property_t *property_p = ecma_get_property_list (obj_p);
property_p != NULL && ecma_is_completion_value_empty (ret_value);
property_p = ECMA_GET_POINTER (ecma_property_t, property_p->next_property_p))
{
ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index);
if (ecma_op_object_get_property (obj_p, index_string_p) != NULL)
ecma_string_t *property_name_p;
if (property_p->type == ECMA_PROPERTY_NAMEDDATA)
{
ECMA_TRY_CATCH (index_value, ecma_op_object_get (obj_p, index_string_p), ret_value);
property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t,
property_p->u.named_data_property.name_p);
}
else if (property_p->type == ECMA_PROPERTY_NAMEDACCESSOR)
{
property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t,
property_p->u.named_accessor_property.name_p);
}
else
{
continue;
}
uint32_t index;
if (ecma_string_get_array_index (property_name_p, &index) && index < len)
{
ECMA_TRY_CATCH (index_value, ecma_op_object_get (obj_p, property_name_p), ret_value);
values_buffer[copied_num++] = ecma_copy_value (index_value, true);
ECMA_FINALIZE (index_value);
}
ecma_deref_ecma_string (index_string_p);
}
JERRY_ASSERT (copied_num <= defined_prop_count);
JERRY_ASSERT (copied_num == defined_prop_count || !ecma_is_completion_value_empty (ret_value));
/* Sorting. */
if (len > 1 && ecma_is_completion_value_empty (ret_value))
if (copied_num > 1 && ecma_is_completion_value_empty (ret_value))
{
ECMA_TRY_CATCH (sort_value,
ecma_builtin_array_prototype_object_array_heap_sort_helper (values_buffer,
@ -1489,8 +1528,7 @@ ecma_builtin_array_prototype_object_sort (ecma_value_t this_arg, /**< this argum
}
/* Put sorted values to the front of the array. */
uint32_t index;
for (index = 0; index < copied_num && ecma_is_completion_value_empty (ret_value); index++)
for (uint32_t index = 0; index < copied_num && ecma_is_completion_value_empty (ret_value); index++)
{
ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index);
ECMA_TRY_CATCH (put_value,
@ -1501,12 +1539,35 @@ ecma_builtin_array_prototype_object_sort (ecma_value_t this_arg, /**< this argum
}
/* Undefined properties should be in the back of the array. */
for (;index < len && ecma_is_completion_value_empty (ret_value); index++)
ecma_property_t *next_prop;
for (ecma_property_t *property_p = ecma_get_property_list (obj_p);
property_p != NULL && ecma_is_completion_value_empty (ret_value);
property_p = next_prop)
{
ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index);
ECMA_TRY_CATCH (del_value, ecma_op_object_delete (obj_p, index_string_p, true), ret_value);
ECMA_FINALIZE (del_value);
ecma_deref_ecma_string (index_string_p);
ecma_string_t *property_name_p;
next_prop = ECMA_GET_POINTER (ecma_property_t, property_p->next_property_p);
if (property_p->type == ECMA_PROPERTY_NAMEDDATA)
{
property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t,
property_p->u.named_data_property.name_p);
}
else if (property_p->type == ECMA_PROPERTY_NAMEDACCESSOR)
{
property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t,
property_p->u.named_accessor_property.name_p);
}
else
{
continue;
}
uint32_t index;
if (ecma_string_get_array_index (property_name_p, &index) && index < len && index >= copied_num)
{
ECMA_TRY_CATCH (del_value, ecma_op_object_delete (obj_p, property_name_p, true), ret_value);
ECMA_FINALIZE (del_value);
}
}
/* Free values that were copied to the local array. */

View File

@ -386,29 +386,8 @@ ecma_op_array_object_define_own_property (ecma_object_t *obj_p, /**< the array o
{
// 4.a.
uint32_t index;
bool is_index;
if (property_name_p->container == ECMA_STRING_CONTAINER_UINT32_IN_DESC)
{
index = property_name_p->u.uint32_number;
is_index = true;
}
else
{
ecma_number_t number = ecma_string_to_number (property_name_p);
index = ecma_number_to_uint32 (number);
ecma_string_t *to_uint32_to_string_p = ecma_new_ecma_string_from_uint32 (index);
is_index = ecma_compare_ecma_strings (property_name_p,
to_uint32_to_string_p);
ecma_deref_ecma_string (to_uint32_to_string_p);
}
is_index = is_index && (index != ECMA_MAX_VALUE_OF_VALID_ARRAY_INDEX);
if (!is_index)
if (!ecma_string_get_array_index (property_name_p, &index))
{
// 5.
return ecma_op_general_object_define_own_property (obj_p,