@@ -770,6 +770,350 @@ ecma_builtin_array_prototype_object_last_index_of (ecma_value_t this_arg, /**< t
770770 return ret_value;
771771} /* ecma_builtin_array_prototype_object_last_index_of */
772772
773+ /* *
774+ * SortCompare abstract method
775+ *
776+ * See also:
777+ * ECMA-262 v5, 15.4.4.11
778+ *
779+ * @return completion value
780+ * Returned value must be freed with ecma_free_completion_value.
781+ */
782+ static ecma_completion_value_t
783+ ecma_builtin_array_prototype_object_sort_compare_helper (ecma_value_t j, /* *< left value */
784+ ecma_value_t k, /* *< right value */
785+ ecma_value_t comparefn) /* *< compare function */
786+ {
787+ /*
788+ * ECMA-262 v5, 15.4.4.11 NOTE1: Because non-existent property values always
789+ * compare greater than undefined property values, and undefined always
790+ * compares greater than any other value, undefined property values always
791+ * sort to the end of the result, followed by non-existent property values.
792+ */
793+ ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
794+ ecma_number_t *result_p = ecma_alloc_number ();
795+
796+ bool j_is_undef = ecma_is_value_undefined (j);
797+ bool k_is_undef = ecma_is_value_undefined (k);
798+
799+ if (j_is_undef)
800+ {
801+ if (k_is_undef)
802+ {
803+ *result_p = ecma_int32_to_number (0 );
804+ }
805+ else
806+ {
807+ *result_p = ecma_int32_to_number (1 );
808+ }
809+ }
810+ else
811+ {
812+ if (k_is_undef)
813+ {
814+ *result_p = ecma_int32_to_number (-1 );
815+ }
816+ else
817+ {
818+ if (ecma_is_value_undefined (comparefn))
819+ {
820+ /* Default comparison when no comparefn is passed. */
821+ ECMA_TRY_CATCH (j_value, ecma_op_to_string (j), ret_value);
822+ ECMA_TRY_CATCH (k_value, ecma_op_to_string (k), ret_value);
823+ ecma_string_t *j_str_p = ecma_get_string_from_value (j_value);
824+ ecma_string_t *k_str_p = ecma_get_string_from_value (k_value);
825+
826+ if (ecma_compare_ecma_strings_relational (j_str_p, k_str_p))
827+ {
828+ *result_p = ecma_int32_to_number (-1 );
829+ }
830+ else if (!ecma_compare_ecma_strings (j_str_p, k_str_p))
831+ {
832+ *result_p = ecma_int32_to_number (1 );
833+ }
834+ else
835+ {
836+ *result_p = ecma_int32_to_number (0 );
837+ }
838+
839+ ECMA_FINALIZE (k_value);
840+ ECMA_FINALIZE (j_value);
841+ }
842+ else
843+ {
844+ /*
845+ * comparefn, if not undefined, will always contain a callable function object.
846+ * We checked this previously, before this function was called.
847+ */
848+ JERRY_ASSERT (ecma_op_is_callable (comparefn));
849+ ecma_object_t *comparefn_obj_p = ecma_get_object_from_value (comparefn);
850+
851+ ecma_value_t compare_args[] = {j, k};
852+
853+ ECMA_TRY_CATCH (call_value,
854+ ecma_op_function_call (comparefn_obj_p,
855+ ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED),
856+ compare_args,
857+ 2 ),
858+ ret_value);
859+
860+ if (!ecma_is_value_number (call_value))
861+ {
862+ ECMA_OP_TO_NUMBER_TRY_CATCH (ret_num, call_value, ret_value);
863+ *result_p = ret_num;
864+ ECMA_OP_TO_NUMBER_FINALIZE (ret_num);
865+ }
866+ else
867+ {
868+ *result_p = *ecma_get_number_from_value (call_value);
869+ }
870+
871+ ECMA_FINALIZE (call_value);
872+ }
873+ }
874+ }
875+
876+ if (ecma_is_completion_value_empty (ret_value))
877+ {
878+ ret_value = ecma_make_normal_completion_value (ecma_make_number_value (result_p));
879+ }
880+ else
881+ {
882+ ecma_dealloc_number (result_p);
883+ }
884+
885+ return ret_value;
886+ } /* ecma_builtin_array_prototype_object_sort_compare_helper */
887+
888+ /* *
889+ * Function used to reconstruct the ordered binary tree.
890+ * Shifts 'index' down in the tree until it is in the correct position.
891+ *
892+ * @return completion value
893+ * Returned value must be freed with ecma_free_completion_value.
894+ */
895+ static ecma_completion_value_t
896+ ecma_builtin_array_prototype_object_array_to_heap_helper (ecma_value_t array[], /* *< heap data array */
897+ int index, /* *< current item index */
898+ int right, /* *< right index is a maximum index */
899+ ecma_value_t comparefn) /* *< compare function */
900+ {
901+ ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
902+
903+ /* Left child of the current index. */
904+ int child = index * 2 + 1 ;
905+ ecma_value_t swap = array[index];
906+ bool should_break = false ;
907+
908+ while (child <= right && ecma_is_completion_value_empty (ret_value) && !should_break)
909+ {
910+ if (child < right)
911+ {
912+ /* Compare the two child nodes. */
913+ ECMA_TRY_CATCH (child_compare_value,
914+ ecma_builtin_array_prototype_object_sort_compare_helper (array[child],
915+ array[child + 1 ],
916+ comparefn),
917+ ret_value);
918+
919+ JERRY_ASSERT (ecma_is_value_number (child_compare_value));
920+
921+ /* Use the child that is greater. */
922+ if (*ecma_get_number_from_value (child_compare_value) < ECMA_NUMBER_ZERO)
923+ {
924+ child++;
925+ }
926+
927+ ECMA_FINALIZE (child_compare_value);
928+ }
929+
930+ if (ecma_is_completion_value_empty (ret_value))
931+ {
932+ JERRY_ASSERT (child <= right);
933+
934+ /* Compare current child node with the swap (tree top). */
935+ ECMA_TRY_CATCH (swap_compare_value,
936+ ecma_builtin_array_prototype_object_sort_compare_helper (array[child],
937+ swap,
938+ comparefn),
939+ ret_value);
940+ JERRY_ASSERT (ecma_is_value_number (swap_compare_value));
941+
942+ if (*ecma_get_number_from_value (swap_compare_value) <= ECMA_NUMBER_ZERO)
943+ {
944+ /* Break from loop if current child is less than swap (tree top) */
945+ should_break = true ;
946+ }
947+ else
948+ {
949+ /* We have to move 'swap' lower in the tree, so shift current child up in the hierarchy. */
950+ int parent = (child - 1 ) / 2 ;
951+ JERRY_ASSERT (parent >= 0 && parent <= right);
952+ array[parent] = array[child];
953+
954+ /* Update child to be the left child of the current node. */
955+ child = child * 2 + 1 ;
956+ }
957+
958+ ECMA_FINALIZE (swap_compare_value);
959+ }
960+ }
961+
962+ if (ecma_is_completion_value_empty (ret_value))
963+ {
964+ /*
965+ * Loop ended, either current child does not exist, or is less than swap.
966+ * This means that 'swap' should be placed in the parent node.
967+ */
968+ int parent = (child - 1 ) / 2 ;
969+ JERRY_ASSERT (parent >= 0 && parent <= right);
970+ array[parent] = swap;
971+
972+ ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_UNDEFINED);
973+ }
974+
975+ return ret_value;
976+ } /* ecma_builtin_array_prototype_object_array_to_heap_helper */
977+
978+ /* *
979+ * Heapsort function
980+ *
981+ * @return completion value
982+ * Returned value must be freed with ecma_free_completion_value.
983+ */
984+ static ecma_completion_value_t
985+ ecma_builtin_array_prototype_object_array_heap_sort_helper (ecma_value_t array[], /* *< array to sort */
986+ int right, /* *< right index */
987+ ecma_value_t comparefn) /* *< compare function */
988+ {
989+ ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
990+
991+ /* First, construct the ordered binary tree from the array. */
992+ for (int i = right / 2 ; i >= 0 && ecma_is_completion_value_empty (ret_value); i--)
993+ {
994+ ECMA_TRY_CATCH (value,
995+ ecma_builtin_array_prototype_object_array_to_heap_helper (array,
996+ i,
997+ right,
998+ comparefn),
999+ ret_value);
1000+ ECMA_FINALIZE (value);
1001+ }
1002+
1003+ /* Sorting elements. */
1004+ for (int i = right; i > 0 && ecma_is_completion_value_empty (ret_value); i--)
1005+ {
1006+ /*
1007+ * The top element will always contain the largest value.
1008+ * Move top to the end, and remove it from the tree.
1009+ */
1010+ ecma_value_t swap = array[0 ];
1011+ array[0 ] = array[i];
1012+ array[i] = swap;
1013+
1014+ /* Rebuild binary tree from the remaining elements. */
1015+ ECMA_TRY_CATCH (value,
1016+ ecma_builtin_array_prototype_object_array_to_heap_helper (array,
1017+ 0 ,
1018+ i - 1 ,
1019+ comparefn),
1020+ ret_value);
1021+ ECMA_FINALIZE (value);
1022+ }
1023+
1024+ return ret_value;
1025+ } /* ecma_builtin_array_prototype_object_array_heap_sort_helper */
1026+
1027+ /* *
1028+ * The Array.prototype object's 'sort' routine
1029+ *
1030+ * See also:
1031+ * ECMA-262 v5, 15.4.4.11
1032+ *
1033+ * @return completion value
1034+ * Returned value must be freed with ecma_free_completion_value.
1035+ */
1036+ static ecma_completion_value_t
1037+ ecma_builtin_array_prototype_object_sort (ecma_value_t this_arg, /* *< this argument */
1038+ ecma_value_t arg1) /* *< comparefn */
1039+ {
1040+ /* Check if the provided compare function is callable. */
1041+ if (!ecma_is_value_undefined (arg1) && !ecma_op_is_callable (arg1))
1042+ {
1043+ return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE));
1044+ }
1045+
1046+ ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
1047+
1048+ ECMA_TRY_CATCH (obj_this,
1049+ ecma_op_to_object (this_arg),
1050+ ret_value);
1051+
1052+ ecma_object_t *obj_p = ecma_get_object_from_value (obj_this);
1053+ ecma_string_t *magic_string_length_p = ecma_get_magic_string (ECMA_MAGIC_STRING_LENGTH);
1054+
1055+ ECMA_TRY_CATCH (len_value,
1056+ ecma_op_object_get (obj_p, magic_string_length_p),
1057+ ret_value);
1058+
1059+ ECMA_OP_TO_NUMBER_TRY_CATCH (len_number, len_value, ret_value);
1060+
1061+ uint32_t len = ecma_number_to_uint32 (len_number);
1062+
1063+ MEM_DEFINE_LOCAL_ARRAY (values_buffer, len, ecma_value_t );
1064+ uint32_t copied_num = 0 ;
1065+
1066+ /* Copy unsorted array into a native c array. */
1067+ for (uint32_t index = 0 ; index < len && ecma_is_completion_value_empty (ret_value); index++)
1068+ {
1069+ ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index);
1070+ ECMA_TRY_CATCH (index_value, ecma_op_object_get (obj_p, index_string_p), ret_value);
1071+
1072+ values_buffer[index] = ecma_copy_value (index_value, true );
1073+ copied_num++;
1074+
1075+ ECMA_FINALIZE (index_value);
1076+ ecma_deref_ecma_string (index_string_p);
1077+ }
1078+
1079+ JERRY_ASSERT (copied_num == len || !ecma_is_completion_value_empty (ret_value));
1080+
1081+ /* Sorting. */
1082+ if (len > 1 && ecma_is_completion_value_empty (ret_value))
1083+ {
1084+ ECMA_TRY_CATCH (sort_value,
1085+ ecma_builtin_array_prototype_object_array_heap_sort_helper (values_buffer,
1086+ (int )(len - 1 ),
1087+ arg1),
1088+ ret_value);
1089+ ECMA_FINALIZE (sort_value);
1090+ }
1091+
1092+ if (ecma_is_completion_value_empty (ret_value))
1093+ {
1094+ /* Casting len to ecma_length_t may overflow, but since ecma_length_t is still at lest 16 bits long,
1095+ with an array of that size, we would run out of memory way before this happens. */
1096+ JERRY_ASSERT ((ecma_length_t ) len == len);
1097+ /* Copy the sorted array into a new array. */
1098+ ret_value = ecma_op_create_array_object (values_buffer, (ecma_length_t ) len, false );
1099+ }
1100+
1101+ /* Free values that were copied to the local array. */
1102+ for (uint32_t index = 0 ; index < copied_num; index++)
1103+ {
1104+ ecma_free_value (values_buffer[index], true );
1105+ }
1106+
1107+ MEM_FINALIZE_LOCAL_ARRAY (values_buffer);
1108+
1109+ ECMA_OP_TO_NUMBER_FINALIZE (len_number);
1110+ ECMA_FINALIZE (len_value);
1111+ ecma_deref_ecma_string (magic_string_length_p);
1112+ ECMA_FINALIZE (obj_this);
1113+
1114+ return ret_value;
1115+ } /* ecma_builtin_array_prototype_object_sort */
1116+
7731117/* *
7741118 * The Array.prototype object's 'shift' routine
7751119 *
0 commit comments