@@ -770,6 +770,331 @@ 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 = 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 = ecma_int32_to_number (0 );
804+ }
805+ else
806+ {
807+ *result = ecma_int32_to_number (1 );
808+ }
809+ }
810+ else
811+ {
812+ if (k_is_undef)
813+ {
814+ *result = 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_completion_value (j_value);
824+ ecma_string_t *k_str_p = ecma_get_string_from_completion_value (k_value);
825+
826+ if (ecma_compare_ecma_strings_relational (j_str_p, k_str_p))
827+ {
828+ *result = ecma_int32_to_number (-1 );
829+ }
830+ else if (!ecma_compare_ecma_strings (j_str_p, k_str_p))
831+ {
832+ *result = ecma_int32_to_number (1 );
833+ }
834+ else
835+ {
836+ *result = 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+ ecma_number_t *num_p = ecma_alloc_number ();
864+ *num_p = ret_num;
865+ ret_value = ecma_make_number_value (num_p);
866+ ECMA_OP_TO_NUMBER_FINALIZE (ret_num);
867+ }
868+ else
869+ {
870+ ecma_number_t *number = ecma_get_number_from_value (call_value);
871+ if (*number < ECMA_NUMBER_ZERO)
872+ {
873+ *result = ecma_int32_to_number (-1 );
874+ }
875+ else if (*number > ECMA_NUMBER_ZERO)
876+ {
877+ *result = ecma_int32_to_number (1 );
878+ }
879+ else
880+ {
881+ *result = ecma_int32_to_number (0 );
882+ }
883+ }
884+
885+ ECMA_FINALIZE (call_value);
886+ }
887+ }
888+ }
889+
890+ if (ecma_is_completion_value_empty (ret_value))
891+ {
892+ ret_value = ecma_make_normal_completion_value (ecma_make_number_value (result));
893+ }
894+ else
895+ {
896+ ecma_dealloc_number (result);
897+ }
898+
899+ return ret_value;
900+ } /* ecma_builtin_array_prototype_object_sort_compare_helper */
901+
902+ /* *
903+ * Shifting an item in the heap data structure
904+ *
905+ * @return completion value
906+ * Returned value must be freed with ecma_free_completion_value.
907+ */
908+ static ecma_completion_value_t
909+ ecma_builtin_array_prototype_object_array_to_heap_helper (ecma_value_t array[], /* *< heap data array */
910+ int index, /* *< current item index */
911+ int right, /* *< right index is a maximum index */
912+ ecma_value_t comparefn) /* *< compare function */
913+ {
914+ ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
915+ int child = 2 * index;
916+ ecma_value_t swap = array[index];
917+
918+ while (child < right && ecma_is_completion_value_empty (ret_value))
919+ {
920+ ECMA_TRY_CATCH (compare_value,
921+ ecma_builtin_array_prototype_object_sort_compare_helper (array[child],
922+ array[child + 1 ],
923+ comparefn),
924+ ret_value);
925+ JERRY_ASSERT (ecma_is_value_number (compare_value));
926+
927+ if ((*ecma_get_number_from_value (compare_value) < ECMA_NUMBER_ZERO))
928+ {
929+ child++;
930+ }
931+
932+ ECMA_TRY_CATCH (inner_compare_value,
933+ ecma_builtin_array_prototype_object_sort_compare_helper (array[child],
934+ swap,
935+ comparefn),
936+ ret_value);
937+ JERRY_ASSERT (ecma_is_value_number (inner_compare_value));
938+
939+ if (*ecma_get_number_from_value (inner_compare_value) <= ECMA_NUMBER_ZERO)
940+ {
941+ /* Break from loop */
942+ ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_UNDEFINED);
943+ }
944+ else
945+ {
946+ array[child / 2 ] = array[child];
947+ child = (child == 0 ) ? 1 : child * 2 ;
948+ }
949+
950+ ECMA_FINALIZE (inner_compare_value);
951+ ECMA_FINALIZE (compare_value);
952+ }
953+
954+ if (ecma_is_completion_value_empty (ret_value) || ecma_is_completion_value_normal (ret_value))
955+ {
956+ array[child / 2 ] = swap;
957+ }
958+
959+ if (ecma_is_completion_value_empty (ret_value))
960+ {
961+ ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_UNDEFINED);
962+ }
963+
964+ return ret_value;
965+ } /* ecma_builtin_array_prototype_object_array_to_heap_helper */
966+
967+ /* *
968+ * Heapsort function
969+ *
970+ * @return completion value
971+ * Returned value must be freed with ecma_free_completion_value.
972+ */
973+ static ecma_completion_value_t
974+ ecma_builtin_array_prototype_object_array_heap_sort_helper (ecma_value_t array[], /* *< array to sort */
975+ int right, /* *< right index */
976+ ecma_value_t comparefn) /* *< compare function */
977+ {
978+ ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
979+
980+ for (int i = right / 2 ; i >= 0 && ecma_is_completion_value_empty (ret_value); i--)
981+ {
982+ ECMA_TRY_CATCH (value,
983+ ecma_builtin_array_prototype_object_array_to_heap_helper (array,
984+ i,
985+ right,
986+ comparefn),
987+ ret_value);
988+ ECMA_FINALIZE (value);
989+ }
990+
991+ for (int i = right; i > 0 && ecma_is_completion_value_empty (ret_value); i--)
992+ {
993+ ecma_value_t swap = array[0 ];
994+ array[0 ] = array[i];
995+ array[i] = swap;
996+ ECMA_TRY_CATCH (value,
997+ ecma_builtin_array_prototype_object_array_to_heap_helper (array,
998+ 0 ,
999+ i - 1 ,
1000+ comparefn),
1001+ ret_value);
1002+ ECMA_FINALIZE (value);
1003+ }
1004+
1005+ return ret_value;
1006+ } /* ecma_builtin_array_prototype_object_array_heap_sort_helper */
1007+
1008+ /* *
1009+ * The Array.prototype object's 'sort' routine
1010+ *
1011+ * See also:
1012+ * ECMA-262 v5, 15.4.4.11
1013+ *
1014+ * @return completion value
1015+ * Returned value must be freed with ecma_free_completion_value.
1016+ */
1017+ static ecma_completion_value_t
1018+ ecma_builtin_array_prototype_object_sort (ecma_value_t this_arg, /* *< this argument */
1019+ ecma_value_t arg1) /* *< comparefn */
1020+ {
1021+ /* Check if the provided compare function is callable. */
1022+ if (!ecma_is_value_undefined (arg1) && !ecma_op_is_callable (arg1))
1023+ {
1024+ return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE));
1025+ }
1026+
1027+ ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
1028+
1029+ ECMA_TRY_CATCH (obj_this,
1030+ ecma_op_to_object (this_arg),
1031+ ret_value);
1032+
1033+ ecma_object_t *obj_p = ecma_get_object_from_value (obj_this);
1034+ ecma_string_t *magic_string_length_p = ecma_get_magic_string (ECMA_MAGIC_STRING_LENGTH);
1035+
1036+ ECMA_TRY_CATCH (len_value,
1037+ ecma_op_object_get (obj_p, magic_string_length_p),
1038+ ret_value);
1039+
1040+ ECMA_OP_TO_NUMBER_TRY_CATCH (len_number, len_value, ret_value);
1041+
1042+ uint32_t len = ecma_number_to_uint32 (len_number);
1043+
1044+ MEM_DEFINE_LOCAL_ARRAY (values_buffer, len, ecma_value_t );
1045+ uint32_t copied_num = 0 ;
1046+
1047+ /* Copy unsorted array into a native c array. */
1048+ for (uint32_t index = 0 ; index < len && ecma_is_completion_value_empty (ret_value); index++)
1049+ {
1050+ ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index);
1051+ ECMA_TRY_CATCH (index_value, ecma_op_object_get (obj_p, index_string_p), ret_value);
1052+
1053+ values_buffer[index] = ecma_copy_value (index_value, true );
1054+ copied_num++;
1055+
1056+ ECMA_FINALIZE (index_value);
1057+ ecma_deref_ecma_string (index_string_p);
1058+ }
1059+
1060+ JERRY_ASSERT (copied_num == len || !ecma_is_completion_value_empty (ret_value));
1061+
1062+ /* Sorting. */
1063+ if (len > 1 && ecma_is_completion_value_empty (ret_value))
1064+ {
1065+ ECMA_TRY_CATCH (sort_value,
1066+ ecma_builtin_array_prototype_object_array_heap_sort_helper (values_buffer,
1067+ (int )(len - 1 ),
1068+ arg1),
1069+ ret_value);
1070+ ECMA_FINALIZE (sort_value);
1071+ }
1072+
1073+ if (ecma_is_completion_value_empty (ret_value))
1074+ {
1075+ /* Casting len to ecma_length_t may overflow, but since ecma_length_t is still at lest 16 bits long,
1076+ with an array of that size, we would run out of memory way before this happens. */
1077+ JERRY_ASSERT ((ecma_length_t ) len == len);
1078+ /* Copy the sorted array into a new array. */
1079+ ret_value = ecma_op_create_array_object (values_buffer, (ecma_length_t ) len, false );
1080+ }
1081+
1082+ /* Free values that were copied to the local array. */
1083+ for (uint32_t index = 0 ; index < copied_num; index++)
1084+ {
1085+ ecma_free_value (values_buffer[index], true );
1086+ }
1087+
1088+ MEM_FINALIZE_LOCAL_ARRAY (values_buffer);
1089+
1090+ ECMA_OP_TO_NUMBER_FINALIZE (len_number);
1091+ ECMA_FINALIZE (len_value);
1092+ ecma_deref_ecma_string (magic_string_length_p);
1093+ ECMA_FINALIZE (obj_this);
1094+
1095+ return ret_value;
1096+ } /* ecma_builtin_array_prototype_object_sort */
1097+
7731098/* *
7741099 * The Array.prototype object's 'shift' routine
7751100 *
0 commit comments