@@ -1109,6 +1109,352 @@ ecma_builtin_array_prototype_object_last_index_of (ecma_value_t this_arg, /**< t
11091109 return ret_value;
11101110} /* ecma_builtin_array_prototype_object_last_index_of */
11111111
1112+ /* *
1113+ * SortCompare abstract method
1114+ *
1115+ * See also:
1116+ * ECMA-262 v5, 15.4.4.11
1117+ *
1118+ * @return completion value
1119+ * Returned value must be freed with ecma_free_completion_value.
1120+ */
1121+ static ecma_completion_value_t
1122+ ecma_builtin_array_prototype_object_sort_compare_helper (ecma_value_t j, /* *< left value */
1123+ ecma_value_t k, /* *< right value */
1124+ ecma_value_t comparefn) /* *< compare function */
1125+ {
1126+ /*
1127+ * ECMA-262 v5, 15.4.4.11 NOTE1: Because non-existent property values always
1128+ * compare greater than undefined property values, and undefined always
1129+ * compares greater than any other value, undefined property values always
1130+ * sort to the end of the result, followed by non-existent property values.
1131+ */
1132+ ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
1133+ ecma_number_t *result_p = ecma_alloc_number ();
1134+
1135+ bool j_is_undef = ecma_is_value_undefined (j);
1136+ bool k_is_undef = ecma_is_value_undefined (k);
1137+
1138+ if (j_is_undef)
1139+ {
1140+ if (k_is_undef)
1141+ {
1142+ *result_p = ecma_int32_to_number (0 );
1143+ }
1144+ else
1145+ {
1146+ *result_p = ecma_int32_to_number (1 );
1147+ }
1148+ }
1149+ else
1150+ {
1151+ if (k_is_undef)
1152+ {
1153+ *result_p = ecma_int32_to_number (-1 );
1154+ }
1155+ else
1156+ {
1157+ if (ecma_is_value_undefined (comparefn))
1158+ {
1159+ /* Default comparison when no comparefn is passed. */
1160+ ECMA_TRY_CATCH (j_value, ecma_op_to_string (j), ret_value);
1161+ ECMA_TRY_CATCH (k_value, ecma_op_to_string (k), ret_value);
1162+ ecma_string_t *j_str_p = ecma_get_string_from_value (j_value);
1163+ ecma_string_t *k_str_p = ecma_get_string_from_value (k_value);
1164+
1165+ if (ecma_compare_ecma_strings_relational (j_str_p, k_str_p))
1166+ {
1167+ *result_p = ecma_int32_to_number (-1 );
1168+ }
1169+ else if (!ecma_compare_ecma_strings (j_str_p, k_str_p))
1170+ {
1171+ *result_p = ecma_int32_to_number (1 );
1172+ }
1173+ else
1174+ {
1175+ *result_p = ecma_int32_to_number (0 );
1176+ }
1177+
1178+ ECMA_FINALIZE (k_value);
1179+ ECMA_FINALIZE (j_value);
1180+ }
1181+ else
1182+ {
1183+ /*
1184+ * comparefn, if not undefined, will always contain a callable function object.
1185+ * We checked this previously, before this function was called.
1186+ */
1187+ JERRY_ASSERT (ecma_op_is_callable (comparefn));
1188+ ecma_object_t *comparefn_obj_p = ecma_get_object_from_value (comparefn);
1189+
1190+ ecma_value_t compare_args[] = {j, k};
1191+
1192+ ECMA_TRY_CATCH (call_value,
1193+ ecma_op_function_call (comparefn_obj_p,
1194+ ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED),
1195+ compare_args,
1196+ 2 ),
1197+ ret_value);
1198+
1199+ if (!ecma_is_value_number (call_value))
1200+ {
1201+ ECMA_OP_TO_NUMBER_TRY_CATCH (ret_num, call_value, ret_value);
1202+ *result_p = ret_num;
1203+ ECMA_OP_TO_NUMBER_FINALIZE (ret_num);
1204+ }
1205+ else
1206+ {
1207+ *result_p = *ecma_get_number_from_value (call_value);
1208+ }
1209+
1210+ ECMA_FINALIZE (call_value);
1211+ }
1212+ }
1213+ }
1214+
1215+ if (ecma_is_completion_value_empty (ret_value))
1216+ {
1217+ ret_value = ecma_make_normal_completion_value (ecma_make_number_value (result_p));
1218+ }
1219+ else
1220+ {
1221+ ecma_dealloc_number (result_p);
1222+ }
1223+
1224+ return ret_value;
1225+ } /* ecma_builtin_array_prototype_object_sort_compare_helper */
1226+
1227+ /* *
1228+ * Function used to reconstruct the ordered binary tree.
1229+ * Shifts 'index' down in the tree until it is in the correct position.
1230+ *
1231+ * @return completion value
1232+ * Returned value must be freed with ecma_free_completion_value.
1233+ */
1234+ static ecma_completion_value_t
1235+ ecma_builtin_array_prototype_object_array_to_heap_helper (ecma_value_t array[], /* *< heap data array */
1236+ int index, /* *< current item index */
1237+ int right, /* *< right index is a maximum index */
1238+ ecma_value_t comparefn) /* *< compare function */
1239+ {
1240+ ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
1241+
1242+ /* Left child of the current index. */
1243+ int child = index * 2 + 1 ;
1244+ ecma_value_t swap = array[index];
1245+ bool should_break = false ;
1246+
1247+ while (child <= right && ecma_is_completion_value_empty (ret_value) && !should_break)
1248+ {
1249+ if (child < right)
1250+ {
1251+ /* Compare the two child nodes. */
1252+ ECMA_TRY_CATCH (child_compare_value,
1253+ ecma_builtin_array_prototype_object_sort_compare_helper (array[child],
1254+ array[child + 1 ],
1255+ comparefn),
1256+ ret_value);
1257+
1258+ JERRY_ASSERT (ecma_is_value_number (child_compare_value));
1259+
1260+ /* Use the child that is greater. */
1261+ if (*ecma_get_number_from_value (child_compare_value) < ECMA_NUMBER_ZERO)
1262+ {
1263+ child++;
1264+ }
1265+
1266+ ECMA_FINALIZE (child_compare_value);
1267+ }
1268+
1269+ if (ecma_is_completion_value_empty (ret_value))
1270+ {
1271+ JERRY_ASSERT (child <= right);
1272+
1273+ /* Compare current child node with the swap (tree top). */
1274+ ECMA_TRY_CATCH (swap_compare_value,
1275+ ecma_builtin_array_prototype_object_sort_compare_helper (array[child],
1276+ swap,
1277+ comparefn),
1278+ ret_value);
1279+ JERRY_ASSERT (ecma_is_value_number (swap_compare_value));
1280+
1281+ if (*ecma_get_number_from_value (swap_compare_value) <= ECMA_NUMBER_ZERO)
1282+ {
1283+ /* Break from loop if current child is less than swap (tree top) */
1284+ should_break = true ;
1285+ }
1286+ else
1287+ {
1288+ /* We have to move 'swap' lower in the tree, so shift current child up in the hierarchy. */
1289+ int parent = (child - 1 ) / 2 ;
1290+ JERRY_ASSERT (parent >= 0 && parent <= right);
1291+ array[parent] = array[child];
1292+
1293+ /* Update child to be the left child of the current node. */
1294+ child = child * 2 + 1 ;
1295+ }
1296+
1297+ ECMA_FINALIZE (swap_compare_value);
1298+ }
1299+ }
1300+
1301+ if (ecma_is_completion_value_empty (ret_value))
1302+ {
1303+ /*
1304+ * Loop ended, either current child does not exist, or is less than swap.
1305+ * This means that 'swap' should be placed in the parent node.
1306+ */
1307+ int parent = (child - 1 ) / 2 ;
1308+ JERRY_ASSERT (parent >= 0 && parent <= right);
1309+ array[parent] = swap;
1310+
1311+ ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_UNDEFINED);
1312+ }
1313+
1314+ return ret_value;
1315+ } /* ecma_builtin_array_prototype_object_array_to_heap_helper */
1316+
1317+ /* *
1318+ * Heapsort function
1319+ *
1320+ * @return completion value
1321+ * Returned value must be freed with ecma_free_completion_value.
1322+ */
1323+ static ecma_completion_value_t
1324+ ecma_builtin_array_prototype_object_array_heap_sort_helper (ecma_value_t array[], /* *< array to sort */
1325+ int right, /* *< right index */
1326+ ecma_value_t comparefn) /* *< compare function */
1327+ {
1328+ ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
1329+
1330+ /* First, construct the ordered binary tree from the array. */
1331+ for (int i = right / 2 ; i >= 0 && ecma_is_completion_value_empty (ret_value); i--)
1332+ {
1333+ ECMA_TRY_CATCH (value,
1334+ ecma_builtin_array_prototype_object_array_to_heap_helper (array,
1335+ i,
1336+ right,
1337+ comparefn),
1338+ ret_value);
1339+ ECMA_FINALIZE (value);
1340+ }
1341+
1342+ /* Sorting elements. */
1343+ for (int i = right; i > 0 && ecma_is_completion_value_empty (ret_value); i--)
1344+ {
1345+ /*
1346+ * The top element will always contain the largest value.
1347+ * Move top to the end, and remove it from the tree.
1348+ */
1349+ ecma_value_t swap = array[0 ];
1350+ array[0 ] = array[i];
1351+ array[i] = swap;
1352+
1353+ /* Rebuild binary tree from the remaining elements. */
1354+ ECMA_TRY_CATCH (value,
1355+ ecma_builtin_array_prototype_object_array_to_heap_helper (array,
1356+ 0 ,
1357+ i - 1 ,
1358+ comparefn),
1359+ ret_value);
1360+ ECMA_FINALIZE (value);
1361+ }
1362+
1363+ return ret_value;
1364+ } /* ecma_builtin_array_prototype_object_array_heap_sort_helper */
1365+
1366+ /* *
1367+ * The Array.prototype object's 'sort' routine
1368+ *
1369+ * See also:
1370+ * ECMA-262 v5, 15.4.4.11
1371+ *
1372+ * @return completion value
1373+ * Returned value must be freed with ecma_free_completion_value.
1374+ */
1375+ static ecma_completion_value_t
1376+ ecma_builtin_array_prototype_object_sort (ecma_value_t this_arg, /* *< this argument */
1377+ ecma_value_t arg1) /* *< comparefn */
1378+ {
1379+ /* Check if the provided compare function is callable. */
1380+ if (!ecma_is_value_undefined (arg1) && !ecma_op_is_callable (arg1))
1381+ {
1382+ return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE));
1383+ }
1384+
1385+ ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
1386+
1387+ ECMA_TRY_CATCH (obj_this,
1388+ ecma_op_to_object (this_arg),
1389+ ret_value);
1390+
1391+ ecma_object_t *obj_p = ecma_get_object_from_value (obj_this);
1392+ ecma_string_t *magic_string_length_p = ecma_get_magic_string (ECMA_MAGIC_STRING_LENGTH);
1393+
1394+ ECMA_TRY_CATCH (len_value,
1395+ ecma_op_object_get (obj_p, magic_string_length_p),
1396+ ret_value);
1397+
1398+ ECMA_OP_TO_NUMBER_TRY_CATCH (len_number, len_value, ret_value);
1399+
1400+ uint32_t len = ecma_number_to_uint32 (len_number);
1401+
1402+ MEM_DEFINE_LOCAL_ARRAY (values_buffer, len, ecma_value_t );
1403+ uint32_t copied_num = 0 ;
1404+
1405+ /* Copy unsorted array into a native c array. */
1406+ for (uint32_t index = 0 ; index < len && ecma_is_completion_value_empty (ret_value); index++)
1407+ {
1408+ ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index);
1409+ ECMA_TRY_CATCH (index_value, ecma_op_object_get (obj_p, index_string_p), ret_value);
1410+
1411+ values_buffer[index] = ecma_copy_value (index_value, true );
1412+ copied_num++;
1413+
1414+ ECMA_FINALIZE (index_value);
1415+ ecma_deref_ecma_string (index_string_p);
1416+ }
1417+
1418+ JERRY_ASSERT (copied_num == len || !ecma_is_completion_value_empty (ret_value));
1419+
1420+ /* Sorting. */
1421+ if (len > 1 && ecma_is_completion_value_empty (ret_value))
1422+ {
1423+ ECMA_TRY_CATCH (sort_value,
1424+ ecma_builtin_array_prototype_object_array_heap_sort_helper (values_buffer,
1425+ (int )(len - 1 ),
1426+ arg1),
1427+ ret_value);
1428+ ECMA_FINALIZE (sort_value);
1429+ }
1430+
1431+ if (ecma_is_completion_value_empty (ret_value))
1432+ {
1433+ /*
1434+ * FIXME: Casting len to ecma_length_t may overflow, but since ecma_length_t is still at least
1435+ * 16 bits long, with an array of that size, we would run out of memory way before this happens.
1436+ */
1437+ JERRY_ASSERT ((ecma_length_t ) len == len);
1438+ /* Copy the sorted array into a new array. */
1439+ ret_value = ecma_op_create_array_object (values_buffer, (ecma_length_t ) len, false );
1440+ }
1441+
1442+ /* Free values that were copied to the local array. */
1443+ for (uint32_t index = 0 ; index < copied_num; index++)
1444+ {
1445+ ecma_free_value (values_buffer[index], true );
1446+ }
1447+
1448+ MEM_FINALIZE_LOCAL_ARRAY (values_buffer);
1449+
1450+ ECMA_OP_TO_NUMBER_FINALIZE (len_number);
1451+ ECMA_FINALIZE (len_value);
1452+ ecma_deref_ecma_string (magic_string_length_p);
1453+ ECMA_FINALIZE (obj_this);
1454+
1455+ return ret_value;
1456+ } /* ecma_builtin_array_prototype_object_sort */
1457+
11121458/* *
11131459 * The Array.prototype object's 'shift' routine
11141460 *
0 commit comments