@@ -770,6 +770,369 @@ 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 = 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
+ * Function used to reconstruct the ordered binary tree.
904
+ * Shifts 'index' down in the tree until it is in the correct position.
905
+ *
906
+ * @return completion value
907
+ * Returned value must be freed with ecma_free_completion_value.
908
+ */
909
+ static ecma_completion_value_t
910
+ ecma_builtin_array_prototype_object_array_to_heap_helper (ecma_value_t array[], /* *< heap data array */
911
+ int index, /* *< current item index */
912
+ int right, /* *< right index is a maximum index */
913
+ ecma_value_t comparefn) /* *< compare function */
914
+ {
915
+ ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
916
+
917
+ /* Left child of the current index. */
918
+ int child = index * 2 + 1 ;
919
+ ecma_value_t swap = array[index];
920
+
921
+ while (child <= right && ecma_is_completion_value_empty (ret_value))
922
+ {
923
+ if (child < right)
924
+ {
925
+ /* Compare the two child nodes. */
926
+ ECMA_TRY_CATCH (child_compare_value,
927
+ ecma_builtin_array_prototype_object_sort_compare_helper (array[child],
928
+ array[child + 1 ],
929
+ comparefn),
930
+ ret_value);
931
+
932
+ JERRY_ASSERT (ecma_is_value_number (child_compare_value));
933
+
934
+ /* Use the child that is greater. */
935
+ if ((*ecma_get_number_from_value (child_compare_value) < ECMA_NUMBER_ZERO))
936
+ {
937
+ child++;
938
+ }
939
+
940
+ ECMA_FINALIZE (child_compare_value);
941
+ }
942
+
943
+ if (!ecma_is_completion_value_empty (ret_value))
944
+ {
945
+ return ret_value;
946
+ }
947
+
948
+ JERRY_ASSERT (child <= right);
949
+
950
+ /* Compare current child node with the swap (tree top). */
951
+ ECMA_TRY_CATCH (swap_compare_value,
952
+ ecma_builtin_array_prototype_object_sort_compare_helper (array[child],
953
+ swap,
954
+ comparefn),
955
+ ret_value);
956
+ JERRY_ASSERT (ecma_is_value_number (swap_compare_value));
957
+
958
+ if (*ecma_get_number_from_value (swap_compare_value) <= ECMA_NUMBER_ZERO)
959
+ {
960
+ /* Break from loop if current child is less than swap (tree top) */
961
+ ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_UNDEFINED);
962
+ }
963
+ else
964
+ {
965
+ /* We have to move 'swap' lower in the tree, so shift current child up in the hierarchy. */
966
+ int parent = (child - 1 ) / 2 ;
967
+ JERRY_ASSERT (parent >= 0 && parent <= right);
968
+ array[parent] = array[child];
969
+
970
+ /* Update child to be the left child of the current node. */
971
+ child = child * 2 + 1 ;
972
+ }
973
+
974
+ ECMA_FINALIZE (swap_compare_value);
975
+ }
976
+
977
+
978
+ if (ecma_is_completion_value_empty (ret_value) || ecma_is_completion_value_normal (ret_value))
979
+ {
980
+ /*
981
+ * Loop ended, either current child does not exist, or is less than swap.
982
+ * This means that 'swap' should be placed in the parent node.
983
+ */
984
+ int parent = (child - 1 ) / 2 ;
985
+ JERRY_ASSERT (parent >= 0 && parent <= right);
986
+ array[parent] = swap;
987
+ }
988
+
989
+ if (ecma_is_completion_value_empty (ret_value))
990
+ {
991
+ ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_UNDEFINED);
992
+ }
993
+
994
+ return ret_value;
995
+ } /* ecma_builtin_array_prototype_object_array_to_heap_helper */
996
+
997
+ /* *
998
+ * Heapsort function
999
+ *
1000
+ * @return completion value
1001
+ * Returned value must be freed with ecma_free_completion_value.
1002
+ */
1003
+ static ecma_completion_value_t
1004
+ ecma_builtin_array_prototype_object_array_heap_sort_helper (ecma_value_t array[], /* *< array to sort */
1005
+ int right, /* *< right index */
1006
+ ecma_value_t comparefn) /* *< compare function */
1007
+ {
1008
+ ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
1009
+
1010
+ /* First, construct the ordered binary tree from the array. */
1011
+ for (int i = right / 2 ; i >= 0 && ecma_is_completion_value_empty (ret_value); i--)
1012
+ {
1013
+ ECMA_TRY_CATCH (value,
1014
+ ecma_builtin_array_prototype_object_array_to_heap_helper (array,
1015
+ i,
1016
+ right,
1017
+ comparefn),
1018
+ ret_value);
1019
+ ECMA_FINALIZE (value);
1020
+ }
1021
+
1022
+ /* Sorting elements. */
1023
+ for (int i = right; i > 0 && ecma_is_completion_value_empty (ret_value); i--)
1024
+ {
1025
+ /*
1026
+ * The top element will always contain the largest value.
1027
+ * Move top to the end, and remove it from the tree.
1028
+ */
1029
+ ecma_value_t swap = array[0 ];
1030
+ array[0 ] = array[i];
1031
+ array[i] = swap;
1032
+
1033
+ /* Rebuild binary tree from the remaining elements. */
1034
+ ECMA_TRY_CATCH (value,
1035
+ ecma_builtin_array_prototype_object_array_to_heap_helper (array,
1036
+ 0 ,
1037
+ i - 1 ,
1038
+ comparefn),
1039
+ ret_value);
1040
+ ECMA_FINALIZE (value);
1041
+ }
1042
+
1043
+ return ret_value;
1044
+ } /* ecma_builtin_array_prototype_object_array_heap_sort_helper */
1045
+
1046
+ /* *
1047
+ * The Array.prototype object's 'sort' routine
1048
+ *
1049
+ * See also:
1050
+ * ECMA-262 v5, 15.4.4.11
1051
+ *
1052
+ * @return completion value
1053
+ * Returned value must be freed with ecma_free_completion_value.
1054
+ */
1055
+ static ecma_completion_value_t
1056
+ ecma_builtin_array_prototype_object_sort (ecma_value_t this_arg, /* *< this argument */
1057
+ ecma_value_t arg1) /* *< comparefn */
1058
+ {
1059
+ /* Check if the provided compare function is callable. */
1060
+ if (!ecma_is_value_undefined (arg1) && !ecma_op_is_callable (arg1))
1061
+ {
1062
+ return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE));
1063
+ }
1064
+
1065
+ ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
1066
+
1067
+ ECMA_TRY_CATCH (obj_this,
1068
+ ecma_op_to_object (this_arg),
1069
+ ret_value);
1070
+
1071
+ ecma_object_t *obj_p = ecma_get_object_from_value (obj_this);
1072
+ ecma_string_t *magic_string_length_p = ecma_get_magic_string (ECMA_MAGIC_STRING_LENGTH);
1073
+
1074
+ ECMA_TRY_CATCH (len_value,
1075
+ ecma_op_object_get (obj_p, magic_string_length_p),
1076
+ ret_value);
1077
+
1078
+ ECMA_OP_TO_NUMBER_TRY_CATCH (len_number, len_value, ret_value);
1079
+
1080
+ uint32_t len = ecma_number_to_uint32 (len_number);
1081
+
1082
+ MEM_DEFINE_LOCAL_ARRAY (values_buffer, len, ecma_value_t );
1083
+ uint32_t copied_num = 0 ;
1084
+
1085
+ /* Copy unsorted array into a native c array. */
1086
+ for (uint32_t index = 0 ; index < len && ecma_is_completion_value_empty (ret_value); index++)
1087
+ {
1088
+ ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index);
1089
+ ECMA_TRY_CATCH (index_value, ecma_op_object_get (obj_p, index_string_p), ret_value);
1090
+
1091
+ values_buffer[index] = ecma_copy_value (index_value, true );
1092
+ copied_num++;
1093
+
1094
+ ECMA_FINALIZE (index_value);
1095
+ ecma_deref_ecma_string (index_string_p);
1096
+ }
1097
+
1098
+ JERRY_ASSERT (copied_num == len || !ecma_is_completion_value_empty (ret_value));
1099
+
1100
+ /* Sorting. */
1101
+ if (len > 1 && ecma_is_completion_value_empty (ret_value))
1102
+ {
1103
+ ECMA_TRY_CATCH (sort_value,
1104
+ ecma_builtin_array_prototype_object_array_heap_sort_helper (values_buffer,
1105
+ (int )(len - 1 ),
1106
+ arg1),
1107
+ ret_value);
1108
+ ECMA_FINALIZE (sort_value);
1109
+ }
1110
+
1111
+ if (ecma_is_completion_value_empty (ret_value))
1112
+ {
1113
+ /* Casting len to ecma_length_t may overflow, but since ecma_length_t is still at lest 16 bits long,
1114
+ with an array of that size, we would run out of memory way before this happens. */
1115
+ JERRY_ASSERT ((ecma_length_t ) len == len);
1116
+ /* Copy the sorted array into a new array. */
1117
+ ret_value = ecma_op_create_array_object (values_buffer, (ecma_length_t ) len, false );
1118
+ }
1119
+
1120
+ /* Free values that were copied to the local array. */
1121
+ for (uint32_t index = 0 ; index < copied_num; index++)
1122
+ {
1123
+ ecma_free_value (values_buffer[index], true );
1124
+ }
1125
+
1126
+ MEM_FINALIZE_LOCAL_ARRAY (values_buffer);
1127
+
1128
+ ECMA_OP_TO_NUMBER_FINALIZE (len_number);
1129
+ ECMA_FINALIZE (len_value);
1130
+ ecma_deref_ecma_string (magic_string_length_p);
1131
+ ECMA_FINALIZE (obj_this);
1132
+
1133
+ return ret_value;
1134
+ } /* ecma_builtin_array_prototype_object_sort */
1135
+
773
1136
/* *
774
1137
* The Array.prototype object's 'shift' routine
775
1138
*
0 commit comments