@@ -770,6 +770,350 @@ ecma_builtin_array_prototype_object_last_index_of (ecma_value_t this_arg, /**< t
770
770
return ret_value;
771
771
} /* ecma_builtin_array_prototype_object_last_index_of */
772
772
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
+
773
1117
/* *
774
1118
* The Array.prototype object's 'shift' routine
775
1119
*
0 commit comments