Refactor Array.prototype.splice to conform ES11 standard (#4172)

The algorithm is based on ECMA-262 v11, 22.1.3.28

JerryScript-DCO-1.0-Signed-off-by: Adam Szilagyi aszilagy@inf.u-szeged.hu
This commit is contained in:
Szilagyi Adam
2020-09-08 10:04:13 +02:00
committed by GitHub
parent 6f29e48fc6
commit 9bffc981cd
2 changed files with 147 additions and 179 deletions
@@ -1252,6 +1252,7 @@ clean_up:
* The Array.prototype object's 'splice' routine * The Array.prototype object's 'splice' routine
* *
* See also: * See also:
* ECMA-262 v11, 22.1.3.28
* ECMA-262 v5, 15.4.4.12 * ECMA-262 v5, 15.4.4.12
* *
* @return ecma value * @return ecma value
@@ -1263,105 +1264,97 @@ ecma_builtin_array_prototype_object_splice (const ecma_value_t args[], /**< argu
ecma_object_t *obj_p, /**< object */ ecma_object_t *obj_p, /**< object */
ecma_length_t len) /**< object's length */ ecma_length_t len) /**< object's length */
{ {
ecma_length_t actual_start = 0;
ecma_length_t actual_delete_count = 0;
ecma_length_t insert_count = 0;
if (args_number > 0)
{
/* ES5.1: 6, ES11: 4. */
if (ECMA_IS_VALUE_ERROR (ecma_builtin_helper_array_index_normalize (args[0],
len,
&actual_start)))
{
return ECMA_VALUE_ERROR;
}
/* ES11: 6. */
if (args_number == 1)
{
actual_delete_count = len - actual_start;
}
/* ES11: 7. */
else
{
insert_count = args_number - 2;
ecma_number_t delete_num;
if (ECMA_IS_VALUE_ERROR (ecma_op_to_integer (args[1], &delete_num)))
{
return ECMA_VALUE_ERROR;
}
/* ES5.1: 7 */
actual_delete_count = (ecma_length_t) (JERRY_MIN (JERRY_MAX (delete_num, 0),
(ecma_number_t) (len - actual_start)));
}
}
ecma_length_t new_length = len + insert_count - actual_delete_count;
#if ENABLED (JERRY_ESNEXT) #if ENABLED (JERRY_ESNEXT)
ecma_value_t new_array = ecma_op_array_species_create (obj_p, 0); /* ES11: 8. */
if (new_length > ECMA_NUMBER_MAX_SAFE_INTEGER)
{
return ecma_raise_type_error (ECMA_ERR_MSG ("Invalid new array length"));
}
/* ES11: 9. */
ecma_value_t new_array = ecma_op_array_species_create (obj_p, actual_delete_count);
if (ECMA_IS_VALUE_ERROR (new_array)) if (ECMA_IS_VALUE_ERROR (new_array))
{ {
return new_array; return new_array;
} }
#else /* !ENABLED (JERRY_ESNEXT) */ #else /* !ENABLED (JERRY_ESNEXT) */
ecma_value_t new_array = ecma_op_create_array_object (NULL, 0, false); /* ES5.1: 2. */
ecma_value_t length = ecma_make_length_value (actual_delete_count);
ecma_value_t new_array = ecma_op_create_array_object (&length, 1, true);
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (new_array)); JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (new_array));
ecma_free_value (length);
#endif /* ENABLED (JERRY_ESNEXT) */ #endif /* ENABLED (JERRY_ESNEXT) */
ecma_object_t *new_array_p = ecma_get_object_from_value (new_array); ecma_object_t *new_array_p = ecma_get_object_from_value (new_array);
ecma_length_t start = 0; /* ES5.1: 8, ES11: 10. */
ecma_length_t delete_count = 0;
if (args_number > 0)
{
/* 5. 6. */
if (ECMA_IS_VALUE_ERROR (ecma_builtin_helper_array_index_normalize (args[0],
len,
&start)))
{
ecma_deref_object (new_array_p);
return ECMA_VALUE_ERROR;
}
/*
* If there is only one argument, that will be the start argument,
* and we must delete the additional elements.
*/
if (args_number == 1)
{
delete_count = len - start;
}
else
{
/* 7. */
ecma_number_t delete_num;
if (ECMA_IS_VALUE_ERROR (ecma_op_to_integer (args[1], &delete_num)))
{
ecma_deref_object (new_array_p);
return ECMA_VALUE_ERROR;
}
if (!ecma_number_is_nan (delete_num))
{
if (ecma_number_is_negative (delete_num))
{
delete_count = 0;
}
else
{
delete_count = ecma_number_is_infinity (delete_num) ? len : ecma_number_to_uint32 (delete_num);
if (delete_count > len - start)
{
delete_count = len - start;
}
}
}
else
{
delete_count = 0;
}
}
}
/* 8-9. */
ecma_length_t k = 0; ecma_length_t k = 0;
for (ecma_length_t del_item_idx; k < delete_count; k++) /* ES5.1: 9, ES11: 11. */
for (; k < actual_delete_count; k++)
{ {
/* 9.a - 9.b */ ecma_length_t from = actual_start + k;
del_item_idx = k + start; ecma_value_t from_present = ecma_op_object_find_by_index (obj_p, from);
ecma_value_t get_value = ecma_op_object_find_by_index (obj_p, del_item_idx); if (ECMA_IS_VALUE_ERROR (from_present))
if (ECMA_IS_VALUE_ERROR (get_value))
{ {
ecma_deref_object (new_array_p); ecma_deref_object (new_array_p);
return get_value; return from_present;
} }
if (ecma_is_value_found (get_value)) if (ecma_is_value_found (from_present))
{ {
/* 9.c.ii */
ecma_value_t put_comp;
#if ENABLED (JERRY_ESNEXT) #if ENABLED (JERRY_ESNEXT)
const uint32_t prop_flags = ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE | ECMA_IS_THROW; const uint32_t prop_flags = ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE | ECMA_IS_THROW;
#else /* !ENABLED (JERRY_ESNEXT) */ #else /* !ENABLED (JERRY_ESNEXT) */
const uint32_t prop_flags = ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE; const uint32_t prop_flags = ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE;
#endif /* ENABLED (JERRY_ESNEXT) */ #endif /* ENABLED (JERRY_ESNEXT) */
put_comp = ecma_builtin_helper_def_prop_by_index (new_array_p,
k, ecma_value_t put_comp = ecma_builtin_helper_def_prop_by_index (new_array_p,
get_value, k,
prop_flags); from_present,
ecma_free_value (get_value); prop_flags);
ecma_free_value (from_present);
#if ENABLED (JERRY_ESNEXT) #if ENABLED (JERRY_ESNEXT)
if (ECMA_IS_VALUE_ERROR (put_comp)) if (ECMA_IS_VALUE_ERROR (put_comp))
{ {
@@ -1375,131 +1368,110 @@ ecma_builtin_array_prototype_object_splice (const ecma_value_t args[], /**< argu
} }
#if ENABLED (JERRY_ESNEXT) #if ENABLED (JERRY_ESNEXT)
ecma_value_t new_set_length_value = ecma_builtin_array_prototype_helper_set_length (new_array_p, /* ES11: 12. */
((ecma_number_t) delete_count)); ecma_value_t set_length = ecma_builtin_array_prototype_helper_set_length (new_array_p,
((ecma_number_t) actual_delete_count));
if (ECMA_IS_VALUE_ERROR (new_set_length_value)) if (ECMA_IS_VALUE_ERROR (set_length))
{ {
ecma_deref_object (new_array_p); ecma_deref_object (new_array_p);
return new_set_length_value; return set_length;
} }
#endif /* ENABLED (JERRY_ESNEXT) */ #endif /* ENABLED (JERRY_ESNEXT) */
/* 11. */ /* ES5.1: 12, ES11: 15. */
uint32_t item_count; if (insert_count < actual_delete_count)
if (args_number > 2)
{ {
item_count = (uint32_t) (args_number - 2); for (k = actual_start; k < len - actual_delete_count; k++)
}
else
{
item_count = 0;
}
const ecma_length_t new_len = len - delete_count + item_count;
if (item_count != delete_count)
{
ecma_length_t from, to;
/* 12. */
if (item_count < delete_count)
{ {
/* 12.b */ ecma_length_t from = k + actual_delete_count;
for (k = start; k < (len - delete_count); k++) ecma_length_t to = k + insert_count;
ecma_value_t from_present = ecma_op_object_find_by_index (obj_p, from);
if (ECMA_IS_VALUE_ERROR (from_present))
{ {
from = k + delete_count; ecma_deref_object (new_array_p);
to = k + item_count; return from_present;
ecma_value_t get_value = ecma_op_object_find_by_index (obj_p, from);
if (ECMA_IS_VALUE_ERROR (get_value))
{
ecma_deref_object (new_array_p);
return get_value;
}
/* 12.b.iii */
ecma_value_t operation_value;
if (ecma_is_value_found (get_value))
{
/* 12.b.iv */
operation_value = ecma_op_object_put_by_index (obj_p, to, get_value, true);
ecma_free_value (get_value);
}
else
{
/* 12.b.v */
operation_value = ecma_op_object_delete_by_index (obj_p, to, true);
}
if (ECMA_IS_VALUE_ERROR (operation_value))
{
ecma_deref_object (new_array_p);
return operation_value;
}
} }
/* 12.d */ ecma_value_t operation_value;
for (k = len; k > new_len; k--)
{
ecma_value_t del_value = ecma_op_object_delete_by_index (obj_p, k - 1, true);
if (ECMA_IS_VALUE_ERROR (del_value)) if (ecma_is_value_found (from_present))
{ {
ecma_deref_object (new_array_p); operation_value = ecma_op_object_put_by_index (obj_p, to, from_present, true);
return del_value; ecma_free_value (from_present);
} }
else
{
operation_value = ecma_op_object_delete_by_index (obj_p, to, true);
}
if (ECMA_IS_VALUE_ERROR (operation_value))
{
ecma_deref_object (new_array_p);
return operation_value;
} }
} }
/* 13. */
else k = len;
for (k = len; k > new_length; k--)
{ {
JERRY_ASSERT (item_count > delete_count); ecma_value_t del_value = ecma_op_object_delete_by_index (obj_p, k - 1, true);
/* 13.b */
for (k = len - delete_count; k > start; k--) if (ECMA_IS_VALUE_ERROR (del_value))
{ {
from = k + delete_count - 1; ecma_deref_object (new_array_p);
to = k + item_count - 1; return del_value;
/* 13.b.iii */ }
ecma_value_t get_value = ecma_op_object_find_by_index (obj_p, from); }
}
/* ES5.1: 13, ES11: 16. */
else if (insert_count > actual_delete_count)
{
for (k = len - actual_delete_count; k > actual_start; k--)
{
ecma_length_t from = k + actual_delete_count - 1;
ecma_length_t to = k + insert_count - 1;
if (ECMA_IS_VALUE_ERROR (get_value)) ecma_value_t from_present = ecma_op_object_find_by_index (obj_p, from);
{
ecma_deref_object (new_array_p);
return get_value;
}
ecma_value_t operation_value; if (ECMA_IS_VALUE_ERROR (from_present))
{
ecma_deref_object (new_array_p);
return from_present;
}
if (ecma_is_value_found (get_value)) ecma_value_t operation_value;
{
/* 13.b.iv */
operation_value = ecma_op_object_put_by_index (obj_p, to, get_value, true);
ecma_free_value (get_value);
}
else
{
/* 13.b.v */
operation_value = ecma_op_object_delete_by_index (obj_p, to, true);
}
if (ECMA_IS_VALUE_ERROR (operation_value)) if (ecma_is_value_found (from_present))
{ {
ecma_deref_object (new_array_p); operation_value = ecma_op_object_put_by_index (obj_p, to, from_present, true);
return operation_value; ecma_free_value (from_present);
} }
else
{
operation_value = ecma_op_object_delete_by_index (obj_p, to, true);
}
if (ECMA_IS_VALUE_ERROR (operation_value))
{
ecma_deref_object (new_array_p);
return operation_value;
} }
} }
} }
/* 15. */ /* ES5.1: 14, ES11: 17. */
k = actual_start;
/* ES5.1: 15, ES11: 18. */
uint32_t idx = 0; uint32_t idx = 0;
for (uint32_t arg_index = 2; arg_index < args_number; arg_index++, idx++) for (uint32_t arg_index = 2; arg_index < args_number; arg_index++, idx++)
{ {
ecma_value_t put_value = ecma_op_object_put_by_index (obj_p, ecma_value_t put_value = ecma_op_object_put_by_index (obj_p,
start + idx, actual_start + idx,
args[arg_index], args[arg_index],
true); true);
@@ -1510,15 +1482,16 @@ ecma_builtin_array_prototype_object_splice (const ecma_value_t args[], /**< argu
} }
} }
/* 16. */ /* ES5.1: 16, ES11: 19. */
ecma_value_t set_length_value = ecma_builtin_array_prototype_helper_set_length (obj_p, ((ecma_number_t) new_len)); ecma_value_t set_new_length = ecma_builtin_array_prototype_helper_set_length (obj_p, ((ecma_number_t) new_length));
if (ECMA_IS_VALUE_ERROR (set_length_value)) if (ECMA_IS_VALUE_ERROR (set_new_length))
{ {
ecma_deref_object (new_array_p); ecma_deref_object (new_array_p);
return set_length_value; return set_new_length;
} }
/* ES5.1: 17, ES11: 20. */
return new_array; return new_array;
} /* ecma_builtin_array_prototype_object_splice */ } /* ecma_builtin_array_prototype_object_splice */
-5
View File
@@ -151,14 +151,9 @@
<test id="built-ins/Array/prototype/slice/create-proto-from-ctor-realm-array.js"><reason></reason></test> <test id="built-ins/Array/prototype/slice/create-proto-from-ctor-realm-array.js"><reason></reason></test>
<test id="built-ins/Array/prototype/slice/create-proto-from-ctor-realm-non-array.js"><reason></reason></test> <test id="built-ins/Array/prototype/slice/create-proto-from-ctor-realm-non-array.js"><reason></reason></test>
<test id="built-ins/Array/prototype/sort/comparefn-nonfunction-call-throws.js"><reason></reason></test> <test id="built-ins/Array/prototype/sort/comparefn-nonfunction-call-throws.js"><reason></reason></test>
<test id="built-ins/Array/prototype/splice/create-non-array-invalid-len.js"><reason></reason></test>
<test id="built-ins/Array/prototype/splice/create-proto-from-ctor-realm-array.js"><reason></reason></test> <test id="built-ins/Array/prototype/splice/create-proto-from-ctor-realm-array.js"><reason></reason></test>
<test id="built-ins/Array/prototype/splice/create-proto-from-ctor-realm-non-array.js"><reason></reason></test> <test id="built-ins/Array/prototype/splice/create-proto-from-ctor-realm-non-array.js"><reason></reason></test>
<test id="built-ins/Array/prototype/splice/create-species-length-exceeding-integer-limit.js"><reason></reason></test>
<test id="built-ins/Array/prototype/splice/create-species-undef-invalid-len.js"><reason></reason></test>
<test id="built-ins/Array/prototype/splice/create-species.js"><reason></reason></test>
<test id="built-ins/Array/prototype/splice/property-traps-order-with-species.js"><reason></reason></test> <test id="built-ins/Array/prototype/splice/property-traps-order-with-species.js"><reason></reason></test>
<test id="built-ins/Array/prototype/splice/throws-if-integer-limit-exceeded.js"><reason></reason></test>
<test id="built-ins/ArrayBuffer/data-allocation-after-object-creation.js"><reason></reason></test> <test id="built-ins/ArrayBuffer/data-allocation-after-object-creation.js"><reason></reason></test>
<test id="built-ins/ArrayBuffer/proto-from-ctor-realm.js"><reason></reason></test> <test id="built-ins/ArrayBuffer/proto-from-ctor-realm.js"><reason></reason></test>
<test id="built-ins/ArrayBuffer/prototype-from-newtarget.js"><reason></reason></test> <test id="built-ins/ArrayBuffer/prototype-from-newtarget.js"><reason></reason></test>