Skip to content

Commit 3f28cb3

Browse files
Zsolt Borbélygalpeter
authored andcommitted
Fix the indexing of Array builtin functions.
The index-dependant builtins didn't handle correctly the positive Infinity value. JerryScript-DCO-1.0-Signed-off-by: Zsolt Borbély [email protected]
1 parent caa1617 commit 3f28cb3

8 files changed

+187
-204
lines changed

jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.cpp

Lines changed: 66 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
2+
* Copyright 2015 University of Szeged.
23
*
34
* Licensed under the Apache License, Version 2.0 (the "License");
45
* you may not use this file except in compliance with the License.
@@ -892,46 +893,20 @@ ecma_builtin_array_prototype_object_index_of (ecma_value_t this_arg, /**< this a
892893
/* 5. */
893894
ECMA_OP_TO_NUMBER_TRY_CATCH (arg_from_idx, arg2, ret_value);
894895

895-
int32_t from_idx_int = ecma_number_to_int32 (arg_from_idx);
896+
uint32_t from_idx = ecma_builtin_helper_array_index_normalize (arg_from_idx, len);
896897

897898
/* 6. */
898-
if (from_idx_int > 0 && (uint32_t) from_idx_int >= len)
899+
if (from_idx >= len)
899900
{
900901
ret_value = ecma_make_normal_completion_value (ecma_make_number_value (num_p));
901902
}
902903
else
903904
{
904-
uint32_t k;
905+
JERRY_ASSERT (from_idx < len);
905906

906-
/* 7 */
907-
if (from_idx_int >= 0)
907+
for (; from_idx < len && *num_p < 0 && ecma_is_completion_value_empty (ret_value); from_idx++)
908908
{
909-
k = (uint32_t) from_idx_int;
910-
}
911-
/* 8. */
912-
else
913-
{
914-
from_idx_int = -from_idx_int;
915-
916-
/* As opposed to the standard, we prevent k from being negative, so that we can use an uint32 */
917-
if ((uint32_t) from_idx_int < len)
918-
{
919-
/* 8.a */
920-
k = len - (uint32_t) from_idx_int;
921-
}
922-
/* If k would've been negative */
923-
else
924-
{
925-
/* 8.b */
926-
k = 0;
927-
}
928-
929-
}
930-
JERRY_ASSERT (k < len);
931-
932-
for (; k < len && *num_p < 0 && ecma_is_completion_value_empty (ret_value); k++)
933-
{
934-
ecma_string_t *idx_str_p = ecma_new_ecma_string_from_uint32 (k);
909+
ecma_string_t *idx_str_p = ecma_new_ecma_string_from_uint32 (from_idx);
935910

936911
/* 9.a */
937912
if (ecma_op_object_get_property (obj_p, idx_str_p) != NULL)
@@ -942,7 +917,7 @@ ecma_builtin_array_prototype_object_index_of (ecma_value_t this_arg, /**< this a
942917
/* 9.b.ii */
943918
if (ecma_op_strict_equality_compare (arg1, get_value))
944919
{
945-
*num_p = ecma_uint32_to_number (k);
920+
*num_p = ecma_uint32_to_number (from_idx);
946921
}
947922

948923
ECMA_FINALIZE (get_value);
@@ -1019,59 +994,75 @@ ecma_builtin_array_prototype_object_last_index_of (ecma_value_t this_arg, /**< t
1019994
}
1020995
else
1021996
{
1022-
uint32_t k = len - 1;
997+
uint32_t from_idx = len - 1;
1023998

1024999
/* 5. */
10251000
if (!ecma_is_value_undefined (arg2))
10261001
{
10271002
ECMA_OP_TO_NUMBER_TRY_CATCH (arg_from_idx, arg2, ret_value);
1028-
int32_t n = ecma_number_to_int32 (arg_from_idx);
10291003

1030-
/* 6. */
1031-
if (n >= 0)
1004+
if (!ecma_number_is_nan (arg_from_idx))
10321005
{
1033-
/* min(n, len - 1)*/
1034-
if ((uint32_t) n > len - 1)
1006+
1007+
if (ecma_number_is_infinity (arg_from_idx))
10351008
{
1036-
k = len - 1;
1009+
from_idx = ecma_number_is_negative (arg_from_idx) ? (uint32_t) -1 : len - 1;
10371010
}
10381011
else
10391012
{
1040-
k = (uint32_t) n;
1013+
int32_t int_from_idx = ecma_number_to_int32 (arg_from_idx);
1014+
1015+
/* 6. */
1016+
if (int_from_idx >= 0)
1017+
{
1018+
/* min(int_from_idx, len - 1)*/
1019+
if ((uint32_t) int_from_idx > len - 1)
1020+
{
1021+
from_idx = len - 1;
1022+
}
1023+
else
1024+
{
1025+
from_idx = (uint32_t) int_from_idx;
1026+
}
1027+
}
1028+
/* 7. */
1029+
else
1030+
{
1031+
int_from_idx = -int_from_idx;
1032+
1033+
/* We prevent from_idx from being negative, so that we can use an uint32 */
1034+
if ((uint32_t) int_from_idx <= len)
1035+
{
1036+
from_idx = len - (uint32_t) int_from_idx;
1037+
}
1038+
else
1039+
{
1040+
/*
1041+
* If from_idx would be negative, we set it to UINT_MAX. See reasoning for this in the comment
1042+
* at the for loop below.
1043+
*/
1044+
from_idx = (uint32_t) -1;
1045+
}
1046+
}
10411047
}
10421048
}
1043-
/* 7. */
10441049
else
10451050
{
1046-
n = -n;
1047-
1048-
/* We prevent k from being negative, so that we can use an uint32 */
1049-
if ((uint32_t) n <= len)
1050-
{
1051-
k = len - (uint32_t) n;
1052-
}
1053-
else
1054-
{
1055-
/*
1056-
* If k would be negative, we set it to UINT_MAX. See reasoning for this in the comment
1057-
* at the for loop below.
1058-
*/
1059-
k = (uint32_t) -1;
1060-
}
1051+
from_idx = 0;
10611052
}
10621053

10631054
ECMA_OP_TO_NUMBER_FINALIZE (arg_from_idx);
10641055
}
10651056

10661057
/* 8.
1067-
* We should break from the loop when k < 0. We can still use an uint32_t for k, and check
1068-
* for an underflow instead. This is safe, because k will always start in [0, len - 1],
1069-
* and len is in [0, UINT_MAX], so k >= len means we've had an underflow, and should stop.
1058+
* We should break from the loop when from_idx < 0. We can still use an uint32_t for from_idx, and check
1059+
* for an underflow instead. This is safe, because from_idx will always start in [0, len - 1],
1060+
* and len is in [0, UINT_MAX], so from_idx >= len means we've had an underflow, and should stop.
10701061
*/
1071-
for (;k < len && *num_p < 0 && ecma_is_completion_value_empty (ret_value); k--)
1062+
for (; from_idx < len && *num_p < 0 && ecma_is_completion_value_empty (ret_value); from_idx--)
10721063
{
10731064
/* 8.a */
1074-
ecma_string_t *idx_str_p = ecma_new_ecma_string_from_uint32 (k);
1065+
ecma_string_t *idx_str_p = ecma_new_ecma_string_from_uint32 (from_idx);
10751066

10761067
/* 8.a */
10771068
if (ecma_op_object_get_property (obj_p, idx_str_p) != NULL)
@@ -1082,7 +1073,7 @@ ecma_builtin_array_prototype_object_last_index_of (ecma_value_t this_arg, /**< t
10821073
/* 8.b.ii */
10831074
if (ecma_op_strict_equality_compare (arg1, get_value))
10841075
{
1085-
*num_p = ecma_uint32_to_number (k);
1076+
*num_p = ecma_uint32_to_number (from_idx);
10861077
}
10871078

10881079
ECMA_FINALIZE (get_value);
@@ -2029,30 +2020,8 @@ ecma_builtin_array_prototype_object_slice (ecma_value_t this_arg, /**< 'this' ar
20292020

20302021
/* 5. */
20312022
ECMA_OP_TO_NUMBER_TRY_CATCH (start_num, arg1, ret_value);
2032-
int32_t relative_start = ecma_number_to_int32 (start_num);
20332023

2034-
/* 6. */
2035-
if (relative_start < 0)
2036-
{
2037-
uint32_t start_abs = (uint32_t) -relative_start;
2038-
2039-
if (start_abs > len)
2040-
{
2041-
start = 0;
2042-
}
2043-
else
2044-
{
2045-
start = len - start_abs;
2046-
}
2047-
}
2048-
else
2049-
{
2050-
start = (uint32_t) relative_start;
2051-
if (start > len)
2052-
{
2053-
start = len;
2054-
}
2055-
}
2024+
start = ecma_builtin_helper_array_index_normalize (start_num, len);
20562025

20572026
/* 7. */
20582027
if (ecma_is_value_undefined (arg2))
@@ -2062,30 +2031,9 @@ ecma_builtin_array_prototype_object_slice (ecma_value_t this_arg, /**< 'this' ar
20622031
else
20632032
{
20642033
/* 7. part 2*/
2065-
ECMA_OP_TO_NUMBER_TRY_CATCH (end_num, arg2, ret_value)
2066-
int32_t relative_end = ecma_number_to_int32 (end_num);
2034+
ECMA_OP_TO_NUMBER_TRY_CATCH (end_num, arg2, ret_value);
20672035

2068-
if (relative_end < 0)
2069-
{
2070-
uint32_t end_abs = (uint32_t) -relative_end;
2071-
2072-
if (end_abs > len)
2073-
{
2074-
end = 0;
2075-
}
2076-
else
2077-
{
2078-
end = len - end_abs;
2079-
}
2080-
}
2081-
else
2082-
{
2083-
end = (uint32_t) relative_end;
2084-
if (end > len)
2085-
{
2086-
end = len;
2087-
}
2088-
}
2036+
end = ecma_builtin_helper_array_index_normalize (end_num, len);
20892037

20902038
ECMA_OP_TO_NUMBER_FINALIZE (end_num);
20912039
}
@@ -2197,29 +2145,7 @@ ecma_builtin_array_prototype_object_splice (ecma_value_t this_arg, /**< this arg
21972145
args[0],
21982146
ret_value);
21992147

2200-
int32_t relative_start = ecma_number_to_int32 (start_num);
2201-
2202-
/* 6. */
2203-
if (relative_start < 0)
2204-
{
2205-
uint32_t start_abs = (uint32_t) - relative_start;
2206-
if (start_abs > len)
2207-
{
2208-
start = 0;
2209-
}
2210-
else
2211-
{
2212-
start = len - start_abs;
2213-
}
2214-
}
2215-
else
2216-
{
2217-
start = (uint32_t) relative_start;
2218-
if (start > len)
2219-
{
2220-
start = len;
2221-
}
2222-
}
2148+
start = ecma_builtin_helper_array_index_normalize (start_num, len);
22232149

22242150
/*
22252151
* If there is only one argument, that will be the start argument,
@@ -2236,22 +2162,22 @@ ecma_builtin_array_prototype_object_splice (ecma_value_t this_arg, /**< this arg
22362162
args[1],
22372163
ret_value);
22382164

2239-
int32_t delete_count_int = ecma_number_to_int32 (delete_num);
2240-
2241-
if (delete_count_int > 0)
2165+
if (!ecma_number_is_nan (delete_num))
22422166
{
2243-
delete_count = (uint32_t) delete_count_int;
2167+
if (ecma_number_is_negative (delete_num))
2168+
{
2169+
delete_count = 0;
2170+
}
2171+
else
2172+
{
2173+
delete_count = ecma_number_is_infinity (delete_num) ? len : ecma_number_to_uint32 (delete_num);
2174+
}
22442175
}
22452176
else
22462177
{
22472178
delete_count = 0;
22482179
}
22492180

2250-
if (len - start < delete_count)
2251-
{
2252-
delete_count = len - start;
2253-
}
2254-
22552181
ECMA_OP_TO_NUMBER_FINALIZE (delete_num);
22562182
}
22572183

jerry-core/ecma/builtin-objects/ecma-builtin-helpers.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,69 @@ ecma_builtin_helper_object_get_properties (ecma_object_t *obj_p, /** < object */
270270
return new_array;
271271
} /* ecma_builtin_helper_object_get_properties */
272272

273+
/**
274+
* Helper function to normalizing an array index
275+
*
276+
* This function clamps the given index to the [0, length] range.
277+
* If the index is negative, it is used as the offset from the end of the array,
278+
* to compute normalized index.
279+
* If the index is greater than the length of the array, the normalized index will be the length of the array.
280+
*
281+
* See also:
282+
* ECMA-262 v5, 15.4.4.10 steps 5-6, 7 (part 2) and 8
283+
* ECMA-262 v5, 15.4.4.12 steps 5-6
284+
* ECMA-262 v5, 15.4.4.14 steps 5
285+
* ECMA-262 v5, 15.5.4.13 steps 4, 5 (part 2) and 6-7
286+
*
287+
* Used by:
288+
* - The Array.prototype.slice routine.
289+
* - The Array.prototype.splice routine.
290+
* - The Array.prototype.indexOf routine.
291+
* - The String.prototype.slice routine.
292+
*
293+
* @return uint32_t - the normalized value of the index
294+
*/
295+
uint32_t
296+
ecma_builtin_helper_array_index_normalize (ecma_number_t index, /**< index */
297+
uint32_t length) /**< array's length */
298+
{
299+
uint32_t norm_index;
300+
301+
if (!ecma_number_is_nan (index))
302+
{
303+
304+
if (ecma_number_is_infinity (index))
305+
{
306+
norm_index = ecma_number_is_negative (index) ? 0 : length;
307+
}
308+
else
309+
{
310+
const int32_t int_index = ecma_number_to_int32 (index);
311+
312+
if (int_index < 0)
313+
{
314+
const uint32_t uint_index = (uint32_t) - int_index;
315+
norm_index = uint_index > length ? 0 : length - uint_index;
316+
}
317+
else
318+
{
319+
norm_index = (uint32_t) int_index;
320+
321+
if (norm_index > length)
322+
{
323+
norm_index = length;
324+
}
325+
}
326+
}
327+
}
328+
else
329+
{
330+
norm_index = 0;
331+
}
332+
333+
return norm_index;
334+
} /* ecma_builtin_helper_array_index_normalize */
335+
273336
/**
274337
* @}
275338
* @}

jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ extern ecma_completion_value_t ecma_builtin_helper_object_to_string (const ecma_
3030
extern ecma_completion_value_t ecma_builtin_helper_get_to_locale_string_at_index (ecma_object_t *obj_p, uint32_t index);
3131
extern ecma_completion_value_t ecma_builtin_helper_object_get_properties (ecma_object_t *obj,
3232
bool only_enumerable_properties);
33+
extern uint32_t ecma_builtin_helper_array_index_normalize (ecma_number_t index, uint32_t length);
3334

3435
/**
3536
* @}

0 commit comments

Comments
 (0)